db-torque-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tfisc...@apache.org
Subject svn commit: r1028130 [2/6] - in /db/torque/torque4/branches/trunk-without-village: torque-runtime/ torque-runtime/src/main/java/org/apache/torque/map/ torque-runtime/src/main/java/org/apache/torque/oid/ torque-runtime/src/main/java/org/apache/torque/om...
Date Wed, 27 Oct 2010 22:52:18 GMT
Modified: db/torque/torque4/branches/trunk-without-village/torque-runtime/src/main/java/org/apache/torque/util/BasePeer.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/branches/trunk-without-village/torque-runtime/src/main/java/org/apache/torque/util/BasePeer.java?rev=1028130&r1=1028129&r2=1028130&view=diff
==============================================================================
--- db/torque/torque4/branches/trunk-without-village/torque-runtime/src/main/java/org/apache/torque/util/BasePeer.java (original)
+++ db/torque/torque4/branches/trunk-without-village/torque-runtime/src/main/java/org/apache/torque/util/BasePeer.java Wed Oct 27 22:52:15 2010
@@ -22,10 +22,11 @@ package org.apache.torque.util;
 import java.io.Serializable;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.sql.Types;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -39,7 +40,6 @@ import org.apache.torque.Database;
 import org.apache.torque.TooManyRowsException;
 import org.apache.torque.Torque;
 import org.apache.torque.TorqueException;
-import org.apache.torque.adapter.DB;
 import org.apache.torque.map.ColumnMap;
 import org.apache.torque.map.DatabaseMap;
 import org.apache.torque.map.MapBuilder;
@@ -49,15 +49,7 @@ import org.apache.torque.om.NumberKey;
 import org.apache.torque.om.ObjectKey;
 import org.apache.torque.om.SimpleKey;
 import org.apache.torque.om.StringKey;
-
-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;
-import com.workingdogs.village.Schema;
-import com.workingdogs.village.TableDataSet;
+import org.apache.torque.om.mapper.RecordMapper;
 
 /**
  * This is the base class for all Peer classes in the system.  Peer
@@ -113,95 +105,6 @@ public abstract class BasePeer
     }
 
     /**
-     * Sets up a Schema for a table.  This schema is then normally
-     * used as the argument for initTableColumns().
-     *
-     * @param tableName The name of the table.
-     * @return A Schema.
-     */
-    public static Schema initTableSchema(String tableName)
-    {
-        return initTableSchema(tableName, Torque.getDefaultDB());
-    }
-
-    /**
-     * Sets up a Schema for a table.  This schema is then normally
-     * used as the argument for initTableColumns
-     *
-     * @param tableName The propery name for the database in the
-     * configuration file.
-     * @param dbName The name of the database.
-     * @return A Schema.
-     */
-    public static Schema initTableSchema(String tableName, String dbName)
-    {
-        Schema schema = null;
-        Connection con = null;
-
-        try
-        {
-            con = Torque.getConnection(dbName);
-            schema = new Schema().schema(con, tableName);
-        }
-        catch (Exception e)
-        {
-            log.error(e);
-            throw new Error("Error in BasePeer.initTableSchema("
-                    + tableName
-                    + "): "
-                    + e.getMessage());
-        }
-        finally
-        {
-            Torque.closeConnection(con);
-        }
-        return schema;
-    }
-
-    /**
-     * Creates a Column array for a table based on its Schema.
-     *
-     * @param schema A Schema object.
-     * @return A Column[].
-     */
-    public static Column[] initTableColumns(Schema schema)
-    {
-        Column[] columns = null;
-        try
-        {
-            int numberOfColumns = schema.numberOfColumns();
-            columns = new Column[numberOfColumns];
-            for (int i = 0; i < numberOfColumns; i++)
-            {
-                columns[i] = schema.column(i + 1);
-            }
-        }
-        catch (Exception e)
-        {
-            log.error(e);
-            throw new Error(
-                "Error in BasePeer.initTableColumns(): " + e.getMessage());
-        }
-        return columns;
-    }
-
-    /**
-     * Convenience method to create a String array of column names.
-     *
-     * @param columns A Column[].
-     * @return A String[].
-     */
-    public static String[] initColumnNames(Column[] columns)
-    {
-        String[] columnNames = new String[columns.length];
-        for (int i = 0; i < columns.length; i++)
-        {
-            columnNames[i] = columns[i].name().toUpperCase();
-        }
-        return columnNames;
-    }
-
-    /**
      * Convenience method to create a String array of criteria keys.
      *
      * @param tableName Name of table.
@@ -368,227 +271,508 @@ public abstract class BasePeer
     /**
      * Method to perform deletes based on values and keys in a Criteria.
      *
-     * @param criteria The criteria to use.
-     * @param tableName the name of the table to delete records from.
-     *         If set to null, the name of the table(s) can be extracted from
-     *         the criteria, but this can cause unexpected results.
-     * @param con A Connection.
+     * @param criteria The criteria to select the records to be deleted,
+     *        not null.
+     * @param tableName the name of the table to delete records from, not null.
+     * @param con The database connection for deletion, not null.
+     *
      * @throws TorqueException Any exceptions caught during processing will be
      *         rethrown wrapped into a TorqueException.
      */
-    public static void doDelete(Criteria criteria, String tableName, Connection con)
-        throws TorqueException
+    public static int doDelete(
+                Criteria criteria,
+                String tableName,
+                Connection connection)
+            throws TorqueException
     {
-        String dbName = criteria.getDbName();
-        final DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
+//        String dbName = criteria.getDbName();
+//        final DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
 
         // This Callback adds all tables to the Table set which
         // are referenced from a cascading criteria. As a result, all
         // data that is referenced through foreign keys will also be
         // deleted.
-        SQLBuilder.TableCallback tc = new SQLBuilder.TableCallback() {
-                public void process (Set<String> tables, String key, Criteria crit)
-                {
-                    if (crit.isCascade())
-                    {
-                        // This steps thru all the columns in the database.
-                        TableMap[] tableMaps = dbMap.getTables();
-                        for (int i = 0; i < tableMaps.length; i++)
-                        {
-                            ColumnMap[] columnMaps = tableMaps[i].getColumns();
-
-                            for (int j = 0; j < columnMaps.length; j++)
-                            {
-                                // Only delete rows where the foreign key is
-                                // also a primary key.  Other rows need
-                                // updating, but that is not implemented.
-                                if (columnMaps[j].isForeignKey()
-                                        && columnMaps[j].isPrimaryKey()
-                                        && key.equals(columnMaps[j].getRelatedName()))
-                                {
-                                    tables.add(tableMaps[i].getName());
-                                    crit.add(columnMaps[j].getFullyQualifiedName(),
-                                            crit.getValue(key));
-                                }
-                            }
-                        }
-                    }
-                }
-            };
+//      TODO: reimplement
+//        SQLBuilder.TableCallback tc = new SQLBuilder.TableCallback() {
+//                public void process (Set<String> tables, String key, Criteria crit)
+//                {
+//                    if (crit.isCascade())
+//                    {
+//                        // This steps thru all the columns in the database.
+//                        TableMap[] tableMaps = dbMap.getTables();
+//                        for (int i = 0; i < tableMaps.length; i++)
+//                        {
+//                            ColumnMap[] columnMaps = tableMaps[i].getColumns();
+//
+//                            for (int j = 0; j < columnMaps.length; j++)
+//                            {
+//                                // Only delete rows where the foreign key is
+//                                // also a primary key.  Other rows need
+//                                // updating, but that is not implemented.
+//                                if (columnMaps[j].isForeignKey()
+//                                        && columnMaps[j].isPrimaryKey()
+//                                        && key.equals(columnMaps[j].getRelatedName()))
+//                                {
+//                                    tables.add(tableMaps[i].getName());
+//                                    crit.add(columnMaps[j].getFullyQualifiedName(),
+//                                            crit.getValue(key));
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//            };
+
+        Query sql = createQuery(criteria);
+
+        sql.setType(Query.Type.DELETE);
+        sql.getFromClause().clear();
+        sql.getFromClause().add(new Query.FromElement(tableName, null, null));
 
-        Set<String> tables;
-        if (tableName == null)
-        {
-            tables = SQLBuilder.getTableSet(criteria, tc);
-        }
-        else
+        PreparedStatement preparedStatement = null;
+        try
         {
-            tables = new HashSet<String>(1);
-            tables.add(tableName);
-        }
+            preparedStatement = connection.prepareStatement(sql.toString());
+            long startTime = System.currentTimeMillis();
+            log.debug("Executing delete " + sql.toString());
 
-        try
+            int affectedRows = preparedStatement.executeUpdate();
+            long queryEndTime = System.currentTimeMillis();
+            log.trace("delete took " + (queryEndTime - startTime)
+                    + " milliseconds");
+
+            preparedStatement.close();
+            preparedStatement = null;
+            return affectedRows;
+        }
+        catch (SQLException e)
         {
-            processTables(criteria, tables, con, new ProcessCallback() {
-                    public void process(String table, String dbName, Record rec)
-                        throws Exception
-                    {
-                        rec.markToBeDeleted();
-                        rec.save();
-                    }
-                });
+            throw new TorqueException(e);
         }
-        catch (Exception e)
+        finally
         {
-            throwTorqueException(e);
+            if (preparedStatement != null)
+            {
+                try
+                {
+                    preparedStatement.close();
+                }
+                catch (SQLException e)
+                {
+                    log.warn("error closing prepared statement", e);
+                }
+            }
         }
     }
 
     /**
-     * Method to perform inserts based on values and keys in a
-     * Criteria.
-     * <p>
-     * If the primary key is auto incremented the data in Criteria
-     * will be inserted and the auto increment value will be returned.
+//     * Method to perform inserts based on values and keys in a
+//     * Criteria.
+//     * <p>
+//     * If the primary key is auto incremented the data in Criteria
+//     * will be inserted and the auto increment value will be returned.
+//     * <p>
+//     * If the primary key is included in Criteria then that value will
+//     * be used to insert the row.
+//     * <p>
+//     * If no primary key is included in Criteria then we will try to
+//     * figure out the primary key from the database map and insert the
+//     * row with the next available id using util.db.IDBroker.
+//     * <p>
+//     * If no primary key is defined for the table the values will be
+//     * inserted as specified in Criteria and -1 will be returned.
+//     *
+//     * @param criteria Object containing values to insert.
+//     * @return An Object which is the id of the row that was inserted
+//     * (if the table has a primary key) or null (if the table does not
+//     * have a primary key).
+//     * @throws TorqueException Any exceptions caught during processing will be
+//     *         rethrown wrapped into a TorqueException.
+//     */
+//    public static ObjectKey doInsert(Criteria criteria) throws TorqueException
+//    {
+//        Connection connection = null;
+//        try
+//        {
+//            connection = Transaction.beginOptional(
+//                    criteria.getDbName(),
+//                    criteria.isUseTransaction());
+//            ObjectKey id = doInsert(criteria, connection);
+//            Transaction.commit(connection);
+//            connection = null;
+//            return id;
+//        }
+//        finally
+//        {
+//            if (connection != null)
+//            {
+//                Transaction.safeRollback(connection);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Method to perform inserts based on values and keys in a
+//     * Criteria.
+//     * <p>
+//     * If the primary key is auto incremented the data in Criteria
+//     * will be inserted and the auto increment value will be returned.
+//     * <p>
+//     * If the primary key is included in Criteria then that value will
+//     * be used to insert the row.
+//     * <p>
+//     * If no primary key is included in Criteria then we will try to
+//     * figure out the primary key from the database map and insert the
+//     * row with the next available id using util.db.IDBroker.
+//     * <p>
+//     * If no primary key is defined for the table the values will be
+//     * inserted as specified in Criteria and null will be returned.
+//     *
+//     * @param criteria Object containing values to insert.
+//     * @param con A Connection.
+//     * @return An Object which is the id of the row that was inserted
+//     * (if the table has a primary key) or null (if the table does not
+//     * have a primary key).
+//     * @throws TorqueException Any exceptions caught during processing will be
+//     *         rethrown wrapped into a TorqueException.
+//     */
+//    public static ObjectKey doInsert(Criteria criteria, Connection con)
+//        throws TorqueException
+//    {
+//        SimpleKey id = null;
+//
+//        // Get the table name and method for determining the primary
+//        // key value.
+//        String table = null;
+//        Iterator<?> keys = criteria.keySet().iterator();
+//        if (keys.hasNext())
+//        {
+//            table = criteria.getTableName((String) keys.next());
+//        }
+//        else
+//        {
+//            throw new TorqueException("Database insert attempted without "
+//                    + "anything specified to insert");
+//        }
+//
+//        String dbName = criteria.getDbName();
+//        Database database = Torque.getDatabase(dbName);
+//        DatabaseMap dbMap = database.getDatabaseMap();
+//        TableMap tableMap = dbMap.getTable(table);
+//        Object keyInfo = tableMap.getPrimaryKeyMethodInfo();
+//        IdGenerator keyGen
+//                = database.getIdGenerator(tableMap.getPrimaryKeyMethod());
+//
+//        ColumnMap pk = getPrimaryKey(criteria);
+//
+//        // If the keyMethod is SEQUENCE or IDBROKERTABLE, get the id
+//        // before the insert.
+//        if (keyGen != null && keyGen.isPriorToInsert())
+//        {
+//            // pk will be null if there is no primary key defined for the table
+//            // we're inserting into.
+//            if (pk != null && !criteria.containsKey(pk.getFullyQualifiedName()))
+//            {
+//                id = getId(pk, keyGen, con, keyInfo);
+//                criteria.add(pk.getFullyQualifiedName(), id.getValue());
+//            }
+//        }
+//
+//        List<String> columnNames = new ArrayList<String>();
+//        List<Object> replacementObjects = new ArrayList<Object>();
+//        for (Object updateValueObject : criteria.entrySet())
+//        {
+//            Map.Entry<?, ?> updateValue = (Map.Entry<?, ?>) updateValueObject;
+//            String columnName = updateValue.getKey().toString();
+//            if (columnName.lastIndexOf(".") != -1)
+//            {
+//                columnName = columnName.substring(
+//                        columnName.lastIndexOf(".") + 1);
+//            }
+//            columnNames.add(columnName);
+//            replacementObjects.add(
+//                    ((Criteria.Criterion) updateValue.getValue()).getValue());
+//        }
+//
+//        StringBuilder query = new StringBuilder("INSERT INTO ")
+//            .append(table)
+//            .append("(")
+//            .append(StringUtils.join(columnNames, ","))
+//            .append(") VALUES (");
+//        for (int i = 0; i < columnNames.size(); ++i)
+//        {
+//            if (i != 0)
+//            {
+//                query.append(",");
+//            }
+//            query.append("?");
+//        }
+//        query.append(")");
+//
+//        PreparedStatement preparedStatement = null;
+//        try
+//        {
+//            preparedStatement = con.prepareStatement(query.toString());
+//            int position = 1;
+//            for (Object replacementObject : replacementObjects)
+//            {
+//                preparedStatement.setObject(position, replacementObject);
+//                position++;
+//            }
+//            long startTime = System.currentTimeMillis();
+//            log.debug("Executing insert " + query.toString()
+//                    + " using parameters " + replacementObjects);
+//
+//            preparedStatement.executeUpdate();
+//            long queryEndTime = System.currentTimeMillis();
+//            log.trace("insert took " + (queryEndTime - startTime)
+//                    + " milliseconds");
+//
+//            preparedStatement.close();
+//            preparedStatement = null;
+//        }
+//        catch (SQLException e)
+//        {
+//            throw new TorqueException(e);
+//        }
+//        finally
+//        {
+//            if (preparedStatement != null)
+//            {
+//                try
+//                {
+//                    preparedStatement.close();
+//                }
+//                catch (SQLException e)
+//                {
+//                    log.warn("error closing prepared statement", e);
+//                }
+//            }
+//        }
+//
+//        // If the primary key column is auto-incremented, get the id
+//        // now.
+//        if (keyGen != null && keyGen.isPostInsert())
+//        {
+//            id = getId(pk, keyGen, con, keyInfo);
+//        }
+//
+//        return id;
+//    }
+
+    /**
+     * Inserts a record into a database table.
      * <p>
-     * If the primary key is included in Criteria then that value will
+     * If the primary key is included in Criteria, then that value will
      * be used to insert the row.
      * <p>
-     * If no primary key is included in Criteria then we will try to
-     * figure out the primary key from the database map and insert the
-     * row with the next available id using util.db.IDBroker.
+     * Otherwise, if the primary key can be generated automatically,
+     * the generated key will be used for the insert and will be returned.
      * <p>
-     * If no primary key is defined for the table the values will be
-     * inserted as specified in Criteria and -1 will be returned.
+     * If no value is given for the primary key is defined and it cannot
+     * be generated automatically or the table has no primary key,
+     * the values will be inserted as specified and null will be returned.
      *
-     * @param criteria Object containing values to insert.
-     * @return An Object which is the id of the row that was inserted
-     * (if the table has a primary key) or null (if the table does not
-     * have a primary key).
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
+     * @param insertValues Contains the values to insert, not null.
+     *
+     * @return the primary key of the inserted row (if the table
+     *         has a primary key) or null (if the table does not have
+     *         a primary key).
+     *
+     * @throws TorqueException if a database error occurs.
      */
-    public static ObjectKey doInsert(Criteria criteria) throws TorqueException
+    public static ObjectKey doInsert(ColumnValues insertValues)
+          throws TorqueException
     {
-        Connection con = null;
-        ObjectKey id = null;
-
+        String databaseName;
+        {
+            TableMap table = insertValues.getTable();
+            if (table == null)
+            {
+                log.debug("doUpdate(): no Table set in updateValues, "
+                        + "using default database");
+                databaseName = Torque.getDefaultDB();
+            }
+            else
+            {
+                databaseName = table.getDatabaseMap().getName();
+            }
+        }
+        Connection connection = null;
         try
         {
-            con = Transaction.beginOptional(
-                    criteria.getDbName(),
-                    criteria.isUseTransaction());
-            id = doInsert(criteria, con);
-            Transaction.commit(con);
+            connection = Transaction.begin(databaseName);
+            ObjectKey id = doInsert(insertValues, connection);
+            Transaction.commit(connection);
+            connection = null;
+            return id;
         }
-        catch (TorqueException e)
+        finally
         {
-            Transaction.safeRollback(con);
-            throw e;
+            if (connection != null)
+            {
+                Transaction.safeRollback(connection);
+            }
         }
-
-        return id;
     }
 
     /**
-     * Method to perform inserts based on values and keys in a
-     * Criteria.
+     * Inserts a record into a database table.
      * <p>
-     * If the primary key is auto incremented the data in Criteria
-     * will be inserted and the auto increment value will be returned.
-     * <p>
-     * If the primary key is included in Criteria then that value will
+     * If the primary key is included in Criteria, then that value will
      * be used to insert the row.
      * <p>
-     * If no primary key is included in Criteria then we will try to
-     * figure out the primary key from the database map and insert the
-     * row with the next available id using util.db.IDBroker.
+     * Otherwise, if the primary key can be generated automatically,
+     * the generated key will be used for the insert and will be returned.
      * <p>
-     * If no primary key is defined for the table the values will be
-     * inserted as specified in Criteria and null will be returned.
-     *
-     * @param criteria Object containing values to insert.
-     * @param con A Connection.
-     * @return An Object which is the id of the row that was inserted
-     * (if the table has a primary key) or null (if the table does not
-     * have a primary key).
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static ObjectKey doInsert(Criteria criteria, Connection con)
-        throws TorqueException
+     * If no value is given for the primary key is defined and it cannot
+     * be generated automatically or the table has no primary key,
+     * the values will be inserted as specified and null will be returned.
+     *
+     * @param insertValues Contains the values to insert, not null.
+     * @param connection the connection to use for the insert, not null.
+     *
+     * @return the primary key of the inserted row (if the table
+     *         has a primary key) or null (if the table does not have
+     *         a primary key).
+     *
+     * @throws TorqueException if a database error occurs.
+     */
+    public static ObjectKey doInsert(
+                ColumnValues insertValues,
+                Connection connection)
+            throws TorqueException
     {
-        SimpleKey id = null;
-
-        // Get the table name and method for determining the primary
-        // key value.
-        String table = null;
-        Iterator<?> keys = criteria.keySet().iterator();
-        if (keys.hasNext())
-        {
-            table = criteria.getTableName((String) keys.next());
-        }
-        else
-        {
-            throw new TorqueException("Database insert attempted without "
-                    + "anything specified to insert");
-        }
-
-        String dbName = criteria.getDbName();
-        Database database = Torque.getDatabase(dbName);
-        DatabaseMap dbMap = database.getDatabaseMap();
-        TableMap tableMap = dbMap.getTable(table);
+        TableMap tableMap = insertValues.getTable();
+        DatabaseMap dbMap = tableMap.getDatabaseMap();
+        Database database = Torque.getDatabase(dbMap.getName());
         Object keyInfo = tableMap.getPrimaryKeyMethodInfo();
         IdGenerator keyGen
                 = database.getIdGenerator(tableMap.getPrimaryKeyMethod());
 
-        ColumnMap pk = getPrimaryKey(criteria);
-
-        // If the keyMethod is SEQUENCE or IDBROKERTABLE, get the id
-        // before the insert.
-        if (keyGen != null && keyGen.isPriorToInsert())
+        SimpleKey id = null;
+        // can currently generate only single column pks, therefore a single
+        // columnMap is ok
+        ColumnMap primaryKey = null;
+        if (keyGen != null)
         {
-            // pk will be null if there is no primary key defined for the table
-            // we're inserting into.
-            if (pk != null && !criteria.containsKey(pk.getFullyQualifiedName()))
+            // fail on multiple pks
+            primaryKey = tableMap.getPrimaryKey();
+
+            // primaryKey will be null if there is no primary key
+            // defined for the table we're inserting into.
+            if (keyGen.isPriorToInsert() && primaryKey != null
+                    && !insertValues.containsKey(
+                            primaryKey.getFullyQualifiedName()))
             {
-                id = getId(pk, keyGen, con, keyInfo);
-                criteria.add(pk.getFullyQualifiedName(), id);
+                id = getId(primaryKey, keyGen, connection, keyInfo);
+                insertValues.put(
+                        primaryKey.getFullyQualifiedName(),
+                        new JdbcTypedValue(id.getValue(), id.getJdbcType()));
             }
         }
 
-        // Use Village to perform the insert.
-        TableDataSet tds = null;
-        try
+        List<String> columnNames = new ArrayList<String>();
+        List<JdbcTypedValue> replacementObjects
+                = new ArrayList<JdbcTypedValue>();
+        for (Map.Entry<String, JdbcTypedValue> columnValue
+                : insertValues.entrySet())
         {
-            String tableName = SQLBuilder.getFullTableName(table, dbName);
-            tds = new TableDataSet(con, tableName);
-            Record rec = tds.addRecord();
-            // not the fully qualified name, insertOrUpdateRecord wants to use table as an index...
-            BasePeer.insertOrUpdateRecord(rec, table, dbName, criteria);
+            String columnName = columnValue.getKey();
+            if (columnName.lastIndexOf(".") != -1)
+            {
+                columnName = columnName.substring(
+                        columnName.lastIndexOf(".") + 1);
+            }
+            columnNames.add(columnName);
+            JdbcTypedValue value = columnValue.getValue();
+            replacementObjects.add(value);
         }
-        catch (DataSetException e)
+
+        StringBuilder query = new StringBuilder("INSERT INTO ")
+            .append(tableMap.getName())
+            .append("(")
+            .append(StringUtils.join(columnNames, ","))
+            .append(") VALUES (");
+        for (int i = 0; i < columnNames.size(); ++i)
         {
-            throwTorqueException(e);
+            if (i != 0)
+            {
+                query.append(",");
+            }
+            query.append("?");
         }
-        catch (SQLException e)
+        query.append(")");
+
+        PreparedStatement preparedStatement = null;
+        try
         {
-            throwTorqueException(e);
+            preparedStatement = connection.prepareStatement(query.toString());
+            int position = 1;
+            for (JdbcTypedValue replacementObject : replacementObjects)
+            {
+                Object value = replacementObject.getValue();
+                if (value != null)
+                {
+                    if (replacementObject.getJdbcType() != Types.BLOB
+                            && replacementObject.getJdbcType() != Types.CLOB)
+                    {
+                        preparedStatement.setObject(
+                                position,
+                                value,
+                                replacementObject.getJdbcType());
+                    }
+                    else
+                    {
+                        preparedStatement.setObject(
+                                position,
+                                value);
+                    }
+                }
+                else
+                {
+                    preparedStatement.setNull(
+                            position,
+                            replacementObject.getJdbcType());
+                }
+                position++;
+            }
+            long startTime = System.currentTimeMillis();
+            log.debug("Executing insert " + query.toString()
+                    + " using parameters " + replacementObjects);
+
+            preparedStatement.executeUpdate();
+            long queryEndTime = System.currentTimeMillis();
+            log.trace("insert took " + (queryEndTime - startTime)
+                    + " milliseconds");
+
+            preparedStatement.close();
+            preparedStatement = null;
         }
-        catch (TorqueException e)
+        catch (SQLException e)
         {
-            throwTorqueException(e);
+            throw new TorqueException(e);
         }
         finally
         {
-            VillageUtils.close(tds);
+            if (preparedStatement != null)
+            {
+                try
+                {
+                    preparedStatement.close();
+                }
+                catch (SQLException e)
+                {
+                    log.warn("error closing prepared statement", e);
+                }
+            }
         }
 
         // If the primary key column is auto-incremented, get the id
         // now.
         if (keyGen != null && keyGen.isPostInsert())
         {
-            id = getId(pk, keyGen, con, keyInfo);
+            id = getId(primaryKey, keyGen, connection, keyInfo);
         }
 
         return id;
@@ -633,66 +817,6 @@ public abstract class BasePeer
     }
 
     /**
-     * Grouping of code used in both doInsert() and doUpdate()
-     * methods.  Sets up a Record for saving.
-     *
-     * @param rec A Record.
-     * @param table Name of table.
-     * @param criteria A Criteria.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    private static void insertOrUpdateRecord(
-        Record rec,
-        String table,
-        String dbName,
-        Criteria criteria)
-        throws TorqueException
-    {
-        DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
-
-        ColumnMap[] columnMaps = dbMap.getTable(table).getColumns();
-        boolean shouldSave = false;
-        for (int j = 0; j < columnMaps.length; j++)
-        {
-            ColumnMap colMap = columnMaps[j];
-            String colName = colMap.getColumnName();
-            String key = new StringBuffer(colMap.getTableName())
-                    .append('.')
-                    .append(colName)
-                    .toString();
-            if (criteria.containsKey(key))
-            {
-                try
-                {
-                    VillageUtils.setVillageValue(criteria, key, rec, colName);
-                    shouldSave = true;
-                }
-                catch (Exception e)
-                {
-                    throwTorqueException(e);
-                }
-            }
-        }
-
-        if (shouldSave)
-        {
-            try
-            {
-                rec.save();
-            }
-            catch (Exception e)
-            {
-                throwTorqueException(e);
-            }
-        }
-        else
-        {
-            throw new TorqueException("No changes to save");
-        }
-    }
-
-    /**
      * Method to create an SQL query for display only based on values in a
      * Criteria.
      *
@@ -742,452 +866,664 @@ public abstract class BasePeer
     }
 
     /**
-     * Returns all results.
+     * Selects rows from a database an maps them to objects.
      *
-     * @param criteria A Criteria.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> doSelectVillageRecords(
-                Criteria criteria)
+     * @param criteria A Criteria specifying the records to select, not null.
+     * @param mapper The mapper creating the objects from the resultSet,
+     *        not null.
+     * @param defaultTableMap The table map used for the
+     *        unqualified columns in the query, not null.
+     *
+     * @return The results of the query, not null.
+     *
+     * @throws TorqueException if querying the database fails.
+     */
+    public static <T> List<T> doSelect(
+                Criteria criteria,
+                RecordMapper<T> mapper,
+                TableMap defaultTableMap)
             throws TorqueException
     {
-        Connection con = null;
-        List<Record> results = null;
-
+        Connection connection = null;
         try
         {
-            con = Transaction.beginOptional(
+            connection = Transaction.beginOptional(
                     criteria.getDbName(),
                     criteria.isUseTransaction());
-            results = doSelectVillageRecords(criteria, con);
-            Transaction.commit(con);
+
+            List<T> result = doSelect(
+                    criteria,
+                    mapper,
+                    defaultTableMap,
+                    connection);
+
+            Transaction.commit(connection);
+            connection = null;
+            return result;
         }
-        catch (TorqueException e)
+        finally
         {
-            Transaction.safeRollback(con);
-            throw e;
+            if (connection != null)
+            {
+                Transaction.safeRollback(connection);
+            }
         }
-        return results;
     }
 
     /**
-     * Returns all results.
+     * Selects rows from a database an maps them to objects.
      *
-     * @param criteria A Criteria.
-     * @param con A Connection.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
+     * @param query the sql query to execute, not null.
+     * @param mapper The mapper creating the objects from the resultSet,
+     *        not null.
+     * @param defaultTableMap The table map used for the
+     *        unqualified columns in the query, not null.
+     * @param dbName The name of the database to create the connection for,
+     *        or null for the default SDB.
+     *
+     * @return The results of the query, not null.
+     *
+     * @throws TorqueException if querying the database fails.
      */
-    public static List<Record> doSelectVillageRecords(
-                Criteria criteria, Connection con)
+    public static <T> List<T> doSelect(
+                String query,
+                RecordMapper<T> mapper,
+                TableMap defaultTableMap,
+                String dbName)
             throws TorqueException
     {
-        Query query = createQuery(criteria);
-        DB dbadapter = Torque.getDB(criteria.getDbName());
-
-        // Call Village depending on the capabilities of the DB
-        return executeQuery(query.toString(),
-                dbadapter.supportsNativeOffset() ? 0 : criteria.getOffset(),
-                dbadapter.supportsNativeLimit() ? -1 : criteria.getLimit(),
-                criteria.isSingleRecord(),
-                con);
+        if (dbName == null)
+        {
+            dbName = Torque.getDefaultDB();
+        }
+        Connection connection = null;
+        try
+        {
+            connection = Transaction.beginOptional(
+                    dbName,
+                    true);
+
+            List<T> result = doSelect(
+                    query,
+                    mapper,
+                    defaultTableMap,
+                    connection);
+
+            Transaction.commit(connection);
+            connection = null;
+            return result;
+        }
+        finally
+        {
+            if (connection != null)
+            {
+                Transaction.safeRollback(connection);
+            }
+        }
     }
 
     /**
-     * Utility method which executes a given sql statement.  This
-     * method should be used for select statements only.  Use
-     * executeStatement for update, insert, and delete operations.
+     * Selects rows from a database an maps them to objects.
      *
-     * @param queryString A String with the sql statement to execute.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> executeQuery(String queryString) throws TorqueException
-    {
-        return executeQuery(queryString, Torque.getDefaultDB(), false);
-    }
-
-    /**
-     * Utility method which executes a given sql statement.  This
-     * method should be used for select statements only.  Use
-     * executeStatement for update, insert, and delete operations.
+     * @param criteria A Criteria specifying the records to select, not null.
+     * @param mapper The mapper creating the objects from the resultSet,
+     *        not null.
+     * @param defaultTableMap The table map used for the
+     *        unqualified columns in the query, not null.
+     * @param connection the database connection, not null.
      *
-     * @param queryString A String with the sql statement to execute.
-     * @param dbName The database to connect to.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> executeQuery(String queryString, String dbName)
-        throws TorqueException
-    {
-        return executeQuery(queryString, dbName, false);
-    }
-
-    /**
-     * Method for performing a SELECT.  Returns all results.
+     * @return The results of the query, not null.
      *
-     * @param queryString A String with the sql statement to execute.
-     * @param dbName The database to connect to.
-     * @param singleRecord Whether or not we want to select only a
-     * single record.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
+     * @throws TorqueException if querying the database fails.
      */
-    public static List<Record> executeQuery(
-        String queryString,
-        String dbName,
-        boolean singleRecord)
-        throws TorqueException
+    public static <T> List<T> doSelect(
+                Criteria criteria,
+                RecordMapper<T> mapper,
+                TableMap defaultTableMap,
+                Connection connection)
+            throws TorqueException
     {
-        return executeQuery(queryString, 0, -1, dbName, singleRecord);
-    }
-
-    /**
-     * Method for performing a SELECT.  Returns all results.
-     *
-     * @param queryString A String with the sql statement to execute.
-     * @param singleRecord Whether or not we want to select only a
-     * single record.
-     * @param con A Connection.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> executeQuery(
-        String queryString,
-        boolean singleRecord,
-        Connection con)
-        throws TorqueException
-    {
-        return executeQuery(queryString, 0, -1, singleRecord, con);
-    }
-
-    /**
-     * Method for performing a SELECT.
-     *
-     * @param queryString A String with the sql statement to execute.
-     * @param start The first row to return.
-     * @param numberOfResults The number of rows to return.
-     * @param dbName The database to connect to.
-     * @param singleRecord Whether or not we want to select only a
-     * single record.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> executeQuery(
-        String queryString,
-        int start,
-        int numberOfResults,
-        String dbName,
-        boolean singleRecord)
-        throws TorqueException
-    {
-        Connection con = null;
-        List<Record> results = null;
-        try
-        {
-            con = Torque.getConnection(dbName);
-            // execute the query
-            results = executeQuery(
-                    queryString,
-                    start,
-                    numberOfResults,
-                    singleRecord,
-                    con);
-        }
-        finally
+        if (connection == null)
         {
-            Torque.closeConnection(con);
+            throw new NullPointerException("connection is null");
         }
-        return results;
-    }
 
-    /**
-     * Method for performing a SELECT.  Returns all results.
-     *
-     * @param queryString A String with the sql statement to execute.
-     * @param start The first row to return.
-     * @param numberOfResults The number of rows to return.
-     * @param singleRecord Whether or not we want to select only a
-     * single record.
-     * @param con A Connection.
-     * @return List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> executeQuery(
-        String queryString,
-        int start,
-        int numberOfResults,
-        boolean singleRecord,
-        Connection con)
-        throws TorqueException
-    {
-        QueryDataSet qds = null;
-        List<Record> results = Collections.emptyList();
+        correctBooleans(criteria, defaultTableMap);
+
+        Database database = Torque.getDatabase(criteria.getDbName());
+        String query = createQuery(criteria).toString();
+
+        Statement statement = null;
+        ResultSet resultSet = null;
         try
         {
-            // execute the query
+            statement = connection.createStatement();
             long startTime = System.currentTimeMillis();
-            qds = new QueryDataSet(con, queryString);
-            if (log.isDebugEnabled())
+            log.debug("Executing query " + query);
+
+            resultSet = statement.executeQuery(query.toString());
+            long queryEndTime = System.currentTimeMillis();
+            log.trace("query took " + (queryEndTime - startTime)
+                    + " milliseconds");
+
+            int offset;
+            if (database.getAdapter().supportsNativeOffset())
             {
-                log.debug("Elapsed time="
-                        + (System.currentTimeMillis() - startTime) + " ms");
+                offset = 0; //database takes care of offset
             }
-            results = getSelectResults(
-                    qds, start, numberOfResults, singleRecord);
-        }
-        catch (DataSetException e)
-        {
-            throwTorqueException(e);
+            else
+            {
+                offset = criteria.getOffset();
+            }
+
+            int limit;
+            if (database.getAdapter().supportsNativeLimit())
+            {
+                limit = -1; //database takes care of offset
+            }
+            else
+            {
+                if (database.getAdapter().supportsNativeOffset())
+                {
+                    limit = criteria.getLimit();
+                }
+                else
+                {
+                    if (criteria.getLimit() == -1 )
+                    {
+                        limit = criteria.getLimit();
+                    }
+                    else
+                    {
+                        limit = offset + criteria.getLimit();
+                    }
+                }
+            }
+
+            List<T> result = new ArrayList<T>();
+            int rowNumber = 0;
+            while (resultSet.next())
+            {
+                if (rowNumber < offset)
+                {
+                    rowNumber++;
+                    continue;
+                }
+                if (limit >= 0 && rowNumber >= limit)
+                {
+                    break;
+                }
+
+                T rowResult = mapper.processRow(resultSet, 0);
+                result.add(rowResult);
+
+                rowNumber++;
+            }
+            long mappingEndTime = System.currentTimeMillis();
+            log.trace("mapping took " + (mappingEndTime - queryEndTime)
+                    + " milliseconds");
+
+            if (criteria.isSingleRecord() && result.size() > 1)
+            {
+                throw new TooManyRowsException("Criteria expected single Record and "
+                        + "Multiple Records were selected");
+            }
+            return result;
         }
         catch (SQLException e)
         {
-            throwTorqueException(e);
+            throw new TorqueException(e);
         }
         finally
         {
-            VillageUtils.close(qds);
+            if (resultSet != null)
+            {
+                try
+                {
+                    resultSet.close();
+                }
+                catch (SQLException e)
+                {
+                    log.warn("error closing resultSet", e);
+                }
+            }
+            if (statement != null)
+            {
+                try
+                {
+                    statement.close();
+                }
+                catch (SQLException e)
+                {
+                    log.warn("error closing statement", e);
+                }
+            }
         }
-        return results;
     }
 
     /**
-     * Returns all records in a QueryDataSet as a List of Record
-     * objects.  Used for functionality like util.LargeSelect.
+     * Selects rows from a database an maps them to objects.
      *
-     * @see #getSelectResults(QueryDataSet, int, int, boolean)
-     * @param qds the QueryDataSet
-     * @return a List of Record objects
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> getSelectResults(QueryDataSet qds)
-        throws TorqueException
-    {
-        return getSelectResults(qds, 0, -1, false);
-    }
-
-    /**
-     * Returns all records in a QueryDataSet as a List of Record
-     * objects.  Used for functionality like util.LargeSelect.
+     * @param query the SQL Query to execute, not null.
+     * @param mapper The mapper creating the objects from the resultSet,
+     *        not null.
+     * @param defaultTableMap The table map used for the
+     *        unqualified columns in the query, not null.
+     * @param connection the database connection, not null.
      *
-     * @see #getSelectResults(QueryDataSet, int, int, boolean)
-     * @param qds the QueryDataSet
-     * @param singleRecord
-     * @return a List of Record objects
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> getSelectResults(QueryDataSet qds, boolean singleRecord)
-        throws TorqueException
-    {
-        return getSelectResults(qds, 0, -1, singleRecord);
-    }
-
-    /**
-     * Returns numberOfResults records in a QueryDataSet as a List
-     * of Record objects.  Starting at record 0.  Used for
-     * functionality like util.LargeSelect.
+     * @return The results of the query, not null.
      *
-     * @see #getSelectResults(QueryDataSet, int, int, boolean)
-     * @param qds the QueryDataSet
-     * @param numberOfResults
-     * @param singleRecord
-     * @return a List of Record objects
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
+     * @throws TorqueException if querying the database fails.
      */
-    public static List<Record> getSelectResults(
-        QueryDataSet qds,
-        int numberOfResults,
-        boolean singleRecord)
-        throws TorqueException
+    public static <T> List<T> doSelect(
+                String query,
+                RecordMapper<T> mapper,
+                TableMap defaultTableMap,
+                Connection connection)
+            throws TorqueException
     {
-        List<Record> results = null;
-        if (numberOfResults != 0)
+        if (connection == null)
         {
-            results = getSelectResults(qds, 0, numberOfResults, singleRecord);
+            throw new NullPointerException("connection is null");
         }
-        return results;
-    }
 
-    /**
-     * Returns numberOfResults records in a QueryDataSet as a List
-     * of Record objects.  Starting at record start.  Used for
-     * functionality like util.LargeSelect.
-     *
-     * @param qds The <code>QueryDataSet</code> to extract results
-     * from.
-     * @param start The index from which to start retrieving
-     * <code>Record</code> objects from the data set.
-     * @param numberOfResults The number of results to return (or
-     * <code> -1</code> for all results).
-     * @param singleRecord Whether or not we want to select only a
-     * single record.
-     * @return A <code>List</code> of <code>Record</code> objects.
-     * @exception TorqueException If any <code>Exception</code> occurs.
-     */
-    public static List<Record> getSelectResults(
-        QueryDataSet qds,
-        int start,
-        int numberOfResults,
-        boolean singleRecord)
-        throws TorqueException
-    {
-        List<Record> results = null;
+        List<T> result = new ArrayList<T>();
+        Statement statement = null;
+        ResultSet resultSet = null;
         try
         {
-            if (numberOfResults < 0)
-            {
-                results = new ArrayList<Record>();
-                qds.fetchRecords();
-            }
-            else
-            {
-                results = new ArrayList<Record>(numberOfResults);
-                qds.fetchRecords(start, numberOfResults);
-            }
-
-            int startRecord = 0;
-
-            //Offset the correct number of records
-            if (start > 0 && numberOfResults <= 0)
-            {
-                startRecord = start;
-            }
+            statement = connection.createStatement();
+            long startTime = System.currentTimeMillis();
+            log.debug("Executing query " + query);
 
-            // Return a List of Record objects.
-            for (int i = startRecord; i < qds.size(); i++)
-            {
-                Record rec = qds.getRecord(i);
-                results.add(rec);
-            }
+            resultSet = statement.executeQuery(query.toString());
+            long queryEndTime = System.currentTimeMillis();
+            log.trace("query took " + (queryEndTime - startTime)
+                    + " milliseconds");
 
-            if (results.size() > 1 && singleRecord)
+            while (resultSet.next())
             {
-                handleMultipleRecords(qds);
+                T rowResult = mapper.processRow(resultSet, 0);
+                result.add(rowResult);
             }
+            long mappingEndTime = System.currentTimeMillis();
+            log.trace("mapping took " + (mappingEndTime - queryEndTime)
+                    + " milliseconds");
         }
-        catch (Exception e)
+        catch (SQLException e)
         {
-            throwTorqueException(e);
+            throw new TorqueException(e);
         }
-        return results;
-    }
-
-    /**
-     * Helper method which returns the primary key contained
-     * in the given Criteria object.
-     *
-     * @param criteria A Criteria.
-     * @return ColumnMap if the Criteria object contains a primary
-     *          key, or null if it doesn't.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    private static ColumnMap getPrimaryKey(Criteria criteria)
-        throws TorqueException
-    {
-        // Assume all the keys are for the same table.
-        String key = (String) criteria.keys().nextElement();
-
-        String table = criteria.getTableName(key);
-        ColumnMap pk = null;
-
-        if (!table.equals(""))
+        finally
         {
-            DatabaseMap dbMap = Torque.getDatabaseMap(criteria.getDbName());
-            if (dbMap == null)
-            {
-                throw new TorqueException("dbMap is null");
-            }
-            if (dbMap.getTable(table) == null)
+            if (resultSet != null)
             {
-                throw new TorqueException("dbMap.getTable() is null");
+                try
+                {
+                    resultSet.close();
+                }
+                catch (SQLException e)
+                {
+                    log.warn("error closing resultSet", e);
+                }
             }
-
-            ColumnMap[] columns = dbMap.getTable(table).getColumns();
-
-            for (int i = 0; i < columns.length; i++)
+            if (statement != null)
             {
-                if (columns[i].isPrimaryKey())
+                try
                 {
-                    pk = columns[i];
-                    break;
+                    statement.close();
+                }
+                catch (SQLException e)
+                {
+                    log.warn("error closing statement", e);
                 }
             }
         }
-        return pk;
+        return result;
     }
 
+//    /**
+//     * Helper method which returns the primary key contained
+//     * in the given Criteria object.
+//     *
+//     * @param criteria A Criteria.
+//     * @return ColumnMap if the Criteria object contains a primary
+//     *          key, or null if it doesn't.
+//     * @throws TorqueException Any exceptions caught during processing will be
+//     *         rethrown wrapped into a TorqueException.
+//     */
+//    private static ColumnMap getPrimaryKey(Criteria criteria)
+//        throws TorqueException
+//    {
+//        // Assume all the keys are for the same table.
+//        String key = (String) criteria.keys().nextElement();
+//
+//        String table = criteria.getTableName(key);
+//        ColumnMap pk = null;
+//
+//        if (!table.equals(""))
+//        {
+//            DatabaseMap dbMap = Torque.getDatabaseMap(criteria.getDbName());
+//            if (dbMap == null)
+//            {
+//                throw new TorqueException("dbMap is null");
+//            }
+//            if (dbMap.getTable(table) == null)
+//            {
+//                throw new TorqueException("dbMap.getTable() is null");
+//            }
+//
+//            ColumnMap[] columns = dbMap.getTable(table).getColumns();
+//
+//            for (int i = 0; i < columns.length; i++)
+//            {
+//                if (columns[i].isPrimaryKey())
+//                {
+//                    pk = columns[i];
+//                    break;
+//                }
+//            }
+//        }
+//        return pk;
+//    }
+//
+//    /**
+//     * Convenience method used to update rows in the DB.  Checks if a
+//     * <i>single</i> int primary key is specified in the Criteria
+//     * object and uses it to perform the udpate.  If no primary key is
+//     * specified an Exception will be thrown.
+//     * <p>
+//     * Use this method for performing an update of the kind:
+//     * <p>
+//     * "WHERE primary_key_id = an int"
+//     * <p>
+//     * To perform an update with non-primary key fields in the WHERE
+//     * clause use doUpdate(criteria, criteria).
+//     *
+//     * @param updateValues A Criteria object containing values used in
+//     *        set clause.
+//     *
+//     * @return the number of affected rows.
+//     *
+//     * @throws TorqueException Any exceptions caught during processing will be
+//     *         rethrown wrapped into a TorqueException.
+//     */
+//    public static int doUpdate(Criteria updateValues) throws TorqueException
+//    {
+//        Connection connection = null;
+//        try
+//        {
+//            connection = Transaction.beginOptional(
+//                    updateValues.getDbName(),
+//                    updateValues.isUseTransaction());
+//            int result = doUpdate(updateValues, connection);
+//            Transaction.commit(connection);
+//            connection = null;
+//            return result;
+//        }
+//        finally
+//        {
+//            if (connection != null)
+//            {
+//                Transaction.safeRollback(connection);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Convenience method used to update rows in the DB.  Checks if a
+//     * <i>single</i> int primary key is specified in the Criteria
+//     * object and uses it to perform the udpate.  If no primary key is
+//     * specified an Exception will be thrown.
+//     * <p>
+//     * Use this method for performing an update of the kind:
+//     * <p>
+//     * "WHERE primary_key_id = an int"
+//     * <p>
+//     * To perform an update with non-primary key fields in the WHERE
+//     * clause use doUpdate(criteria, criteria).
+//     *
+//     * @param updateValues A Criteria object containing values used in
+//     * set clause.
+//     * @param con A Connection.
+//     * 
+//     * @return the number of affected rows.
+//     *
+//     * @throws TorqueException Any exceptions caught during processing will be
+//     *         rethrown wrapped into a TorqueException.
+//     */
+//    public static int doUpdate(Criteria updateValues, Connection con)
+//        throws TorqueException
+//    {
+//        ColumnMap pk = getPrimaryKey(updateValues);
+//        Criteria selectCriteria = null;
+//
+//        if (pk != null && updateValues.containsKey(pk.getFullyQualifiedName()))
+//        {
+//            selectCriteria = new Criteria(2);
+//            selectCriteria.put(pk.getFullyQualifiedName(),
+//                updateValues.remove(pk.getFullyQualifiedName()));
+//        }
+//        else
+//        {
+//            throw new TorqueException("No PK specified for database update");
+//        }
+//
+//        return doUpdate(selectCriteria, updateValues, con);
+//    }
+//
+//    /**
+//     * Executes an update against the database. The rows to be updated
+//     * are selected using <code>criteria</code> and updated using the values
+//     * in <code>updateValues</code>.
+//     *
+//     * @param criteria selects which rows of which table should be updated.
+//     * @param updateValues which columns(map keys) should be set to which
+//     *        values.
+//     * @param connection the database connection to use, not null.
+//     *
+//     * @return the number of affected rows.
+//     *
+//     * @throws TorqueException if updating fails.
+//     */
+//    public static void doUpdate(
+//                Criteria selectCriteria,
+//                Criteria updateValues)
+//            throws TorqueException
+//    {
+//        Connection con = null;
+//        try
+//        {
+//            con = Transaction.beginOptional(
+//                    selectCriteria.getDbName(),
+//                    selectCriteria.isUseTransaction());
+//            doUpdate(selectCriteria, updateValues, con);
+//            Transaction.commit(con);
+//        }
+//        catch (TorqueException e)
+//        {
+//            Transaction.safeRollback(con);
+//            throw e;
+//        }
+//    }
+//
+//    /**
+//     * Executes an update against the database. The rows to be updated
+//     * are selected using <code>criteria</code> and updated using the values
+//     * in <code>updateValues</code>.
+//     *
+//     * @param criteria selects which rows of which table should be updated.
+//     * @param updateValues which columns(map keys) should be set to which
+//     *        values.
+//     * @param connection the database connection to use, not null.
+//     *
+//     * @return the number of affected rows.
+//     *
+//     * @throws TorqueException if updating fails.
+//     */
+//    public static int doUpdate(
+//                Criteria criteria,
+//                Criteria updateValues,
+//                Connection connection)
+//            throws TorqueException
+//    {
+//        Query sql = createQuery(criteria);
+//        sql.setType(Query.Type.UPDATE);
+//
+//        // ignore select columns in criteria
+//        sql.getSelectClause().clear();
+//        List<Object> replacementObjects = new ArrayList<Object>();
+//        for (Object updateValueObject : updateValues.entrySet())
+//        {
+//            Map.Entry<?, ?> updateValue = (Map.Entry<?, ?>) updateValueObject;
+//            String columnName = updateValue.getKey().toString();
+//            if (columnName.lastIndexOf(".") != -1)
+//            {
+//                columnName = columnName.substring(
+//                        columnName.lastIndexOf(".") + 1);
+//            }
+//            sql.getSelectClause().add(columnName);
+//            replacementObjects.add(
+//                    ((Criteria.Criterion) updateValue.getValue()).getValue());
+//        }
+//
+//        PreparedStatement preparedStatement = null;
+//        try
+//        {
+//            preparedStatement = connection.prepareStatement(sql.toString());
+//            int position = 1;
+//            for (Object replacementObject : replacementObjects)
+//            {
+//                preparedStatement.setObject(position, replacementObject);
+//                position++;
+//            }
+//            long startTime = System.currentTimeMillis();
+//            log.debug("Executing update " + sql.toString()
+//                    + " using parameters " + replacementObjects);
+//
+//            int affectedRows = preparedStatement.executeUpdate();
+//            long queryEndTime = System.currentTimeMillis();
+//            log.trace("update took " + (queryEndTime - startTime)
+//                    + " milliseconds");
+//
+//            preparedStatement.close();
+//            preparedStatement = null;
+//            return affectedRows;
+//        }
+//        catch (SQLException e)
+//        {
+//            throw new TorqueException(e);
+//        }
+//        finally
+//        {
+//            if (preparedStatement != null)
+//            {
+//                try
+//                {
+//                    preparedStatement.close();
+//                }
+//                catch (SQLException e)
+//                {
+//                    log.warn("error closing prepared statement", e);
+//                }
+//            }
+//        }
+//    }
+
+
     /**
      * Convenience method used to update rows in the DB.  Checks if a
-     * <i>single</i> int primary key is specified in the Criteria
-     * object and uses it to perform the udpate.  If no primary key is
-     * specified an Exception will be thrown.
+     * <i>single</i> primary key is specified in the Criteria
+     * object and uses it to perform the update.  If no primary key is
+     * specified or the table has multiple primary keys,
+     * an Exception will be thrown.
      * <p>
      * Use this method for performing an update of the kind:
      * <p>
-     * "WHERE primary_key_id = an int"
+     * "WHERE primary_key_id = someValue"
      * <p>
-     * To perform an update with non-primary key fields in the WHERE
-     * clause use doUpdate(criteria, criteria).
+     * To perform an update on a table with multiple primary keys or 
+     * an update with non-primary key fields in the WHERE
+     * clause, use doUpdate(ColumnValues, Criteria).
+     *
+     * @param updateValues Which columns to update with which values
+     *        for which primary key value, not null.
+     *
+     * @return the number of affected rows.
      *
-     * @param updateValues A Criteria object containing values used in
-     *        set clause.
      * @throws TorqueException Any exceptions caught during processing will be
      *         rethrown wrapped into a TorqueException.
      */
-    public static void doUpdate(Criteria updateValues) throws TorqueException
+    public static int doUpdate(ColumnValues updateValues)
+            throws TorqueException
     {
-        Connection con = null;
+        String databaseName;
+        {
+            TableMap table = updateValues.getTable();
+            if (table == null)
+            {
+                log.debug("doUpdate(): no Table set in updateValues, "
+                        + "using default database");
+                databaseName = Torque.getDefaultDB();
+            }
+            else
+            {
+                databaseName = table.getDatabaseMap().getName();
+            }
+        }
+        Connection connection = null;
         try
         {
-            con = Transaction.beginOptional(
-                    updateValues.getDbName(),
-                    updateValues.isUseTransaction());
-            doUpdate(updateValues, con);
-            Transaction.commit(con);
+            connection = Transaction.begin(databaseName);
+            int result = doUpdate(updateValues, connection);
+            Transaction.commit(connection);
+            connection = null;
+            return result;
         }
-        catch (TorqueException e)
+        finally
         {
-            Transaction.safeRollback(con);
-            throw e;
+            if (connection != null)
+            {
+                Transaction.safeRollback(connection);
+            }
         }
     }
 
     /**
      * Convenience method used to update rows in the DB.  Checks if a
-     * <i>single</i> int primary key is specified in the Criteria
-     * object and uses it to perform the udpate.  If no primary key is
-     * specified an Exception will be thrown.
+     * <i>single</i> primary key is specified in the Criteria
+     * object and uses it to perform the update.  If no primary key is
+     * specified or the table has multiple primary keys,
+     * an Exception will be thrown.
      * <p>
      * Use this method for performing an update of the kind:
      * <p>
-     * "WHERE primary_key_id = an int"
+     * "WHERE primary_key_id = someValue"
      * <p>
-     * To perform an update with non-primary key fields in the WHERE
-     * clause use doUpdate(criteria, criteria).
+     * To perform an update on a table with multiple primary keys or 
+     * an update with non-primary key fields in the WHERE
+     * clause, use doUpdate(ColumnValues, Criteria, Connection).
+     *
+     * @param updateValues Which columns to update with which values
+     *        for which primary key value, not null.
+     * @param connection the database connection to use.
+     *
+     * @return the number of affected rows.
+     *
+     * @param updateValues A map keyed by the column names
+     *        containing the column's values in its values.
+     * @param connection the database connection to use.
      *
-     * @param updateValues A Criteria object containing values used in
-     * set clause.
-     * @param con A Connection.
      * @throws TorqueException Any exceptions caught during processing will be
      *         rethrown wrapped into a TorqueException.
      */
-    public static void doUpdate(Criteria updateValues, Connection con)
-        throws TorqueException
+    public static int doUpdate(
+                ColumnValues updateValues,
+                Connection connection)
+            throws TorqueException
     {
-        ColumnMap pk = getPrimaryKey(updateValues);
+        TableMap table = updateValues.getTable();
+        ColumnMap pk = table.getPrimaryKey();
         Criteria selectCriteria = null;
 
         if (pk != null && updateValues.containsKey(pk.getFullyQualifiedName()))
@@ -1201,83 +1537,147 @@ public abstract class BasePeer
             throw new TorqueException("No PK specified for database update");
         }
 
-        doUpdate(selectCriteria, updateValues, con);
+        return doUpdate(selectCriteria, updateValues, connection);
     }
 
     /**
-     * Method used to update rows in the DB.  Rows are selected based
-     * on selectCriteria and updated using values in updateValues.
-     * <p>
-     * 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...
+     * Executes an update against the database. The rows to be updated
+     * are selected using <code>criteria</code> and updated using the values
+     * in <code>updateValues</code>.
      *
-     * @param selectCriteria A Criteria object containing values used in where
-     *        clause.
-     * @param updateValues A Criteria object containing values used in set
-     *        clause.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
+     * @param criteria selects which rows of which table should be updated.
+     * @param updateValues Which columns to update with which values, not null.
+     *
+     * @return the number of affected rows.
+     *
+     * @throws TorqueException if updating fails.
      */
-    public static void doUpdate(Criteria selectCriteria, Criteria updateValues)
-        throws TorqueException
+    public static int doUpdate(
+                Criteria selectCriteria,
+                ColumnValues updateValues)
+            throws TorqueException
     {
-        Connection con = null;
+        String databaseName;
+        {
+            TableMap table = updateValues.getTable();
+            if (table == null)
+            {
+                log.debug("doUpdate(): no Table set in updateValues, "
+                        + "using default database");
+                databaseName = Torque.getDefaultDB();
+            }
+            else
+            {
+                databaseName = table.getDatabaseMap().getName();
+            }
+        }
+        Connection connection = null;
         try
         {
-            con = Transaction.beginOptional(
-                    selectCriteria.getDbName(),
-                    updateValues.isUseTransaction());
-            doUpdate(selectCriteria, updateValues, con);
-            Transaction.commit(con);
+            connection = Transaction.begin(databaseName);
+            int result = doUpdate(selectCriteria, updateValues, connection);
+            Transaction.commit(connection);
+            connection = null;
+            return result;
         }
-        catch (TorqueException e)
+        finally
         {
-            Transaction.safeRollback(con);
-            throw e;
+            if (connection != null)
+            {
+                Transaction.safeRollback(connection);
+            }
         }
     }
 
     /**
-     * Method used to update rows in the DB.  Rows are selected based
-     * on criteria and updated using values in updateValues.
-     * <p>
-     * 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.
+     * Executes an update against the database. The rows to be updated
+     * are selected using <code>criteria</code> and updated using the values
+     * in <code>updateValues</code>.
      *
-     * @param criteria A Criteria object containing values used in where
-     *        clause.
-     * @param updateValues A Criteria object containing values used in set
-     *        clause.
-     * @param con A Connection.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
+     * @param criteria selects which rows of which table should be updated.
+     * @param updateValues Which columns to update with which values, not null.
+     * @param connection the database connection to use, not null.
+     *
+     * @return the number of affected rows.
+     *
+     * @throws TorqueException if updating fails.
      */
-    public static void doUpdate(
-        Criteria criteria,
-        final Criteria updateValues,
-        Connection con)
-        throws TorqueException
+    public static int doUpdate(
+                Criteria criteria,
+                ColumnValues updateValues,
+                Connection connection)
+            throws TorqueException
     {
-        Set<String> tables = SQLBuilder.getTableSet(criteria, null);
+        Query sql = createQuery(criteria);
+        sql.setType(Query.Type.UPDATE);
 
+        // ignore select columns in criteria
+        sql.getSelectClause().clear();
+        List<JdbcTypedValue> replacementObjects
+                = new ArrayList<JdbcTypedValue>();
+        for (Map.Entry<String, JdbcTypedValue> updateValue
+                : updateValues.entrySet())
+        {
+            String columnName = updateValue.getKey();
+            if (columnName.lastIndexOf(".") != -1)
+            {
+                columnName = columnName.substring(
+                        columnName.lastIndexOf(".") + 1);
+            }
+            sql.getSelectClause().add(columnName);
+            replacementObjects.add(updateValue.getValue());
+        }
+
+        PreparedStatement preparedStatement = null;
         try
         {
-            processTables(criteria, tables, con, new ProcessCallback() {
-                    public void process (String table, String dbName, Record rec)
-                        throws Exception
-                    {
-                        // Callback must be called with table name without Schema!
-                        BasePeer.insertOrUpdateRecord(rec, table, dbName, updateValues);
-                    }
-                });
+            preparedStatement = connection.prepareStatement(sql.toString());
+            int position = 1;
+            for (JdbcTypedValue replacementObject : replacementObjects)
+            {
+                Object value = replacementObject.getValue();
+                if (value != null)
+                {
+                    preparedStatement.setObject(position, value);
+                }
+                else
+                {
+                    preparedStatement.setNull(
+                            position,
+                            replacementObject.getJdbcType());
+                }
+                position++;
+            }
+            long startTime = System.currentTimeMillis();
+            log.debug("Executing update " + sql.toString()
+                    + " using parameters " + replacementObjects);
+
+            int affectedRows = preparedStatement.executeUpdate();
+            long queryEndTime = System.currentTimeMillis();
+            log.trace("update took " + (queryEndTime - startTime)
+                    + " milliseconds");
+
+            preparedStatement.close();
+            preparedStatement = null;
+            return affectedRows;
         }
-        catch (Exception e)
+        catch (SQLException e)
         {
-            throwTorqueException(e);
+            throw new TorqueException(e);
+        }
+        finally
+        {
+            if (preparedStatement != null)
+            {
+                try
+                {
+                    preparedStatement.close();
+                }
+                catch (SQLException e)
+                {
+                    log.warn("error closing prepared statement", e);
+                }
+            }
         }
     }
 
@@ -1367,23 +1767,6 @@ public abstract class BasePeer
     }
 
     /**
-     * If the user specified that (s)he only wants to retrieve a
-     * single record and multiple records are retrieved, this method
-     * is called to handle the situation.  The default behavior is to
-     * throw an exception, but subclasses can override this method as
-     * needed.
-     *
-     * @param ds The DataSet which contains multiple records.
-     * @exception TooManyRowsException Couldn't handle multiple records.
-     */
-    protected static void handleMultipleRecords(DataSet ds)
-        throws TooManyRowsException
-    {
-        throw new TooManyRowsException("Criteria expected single Record and "
-                + "Multiple Records were selected");
-    }
-
-    /**
      * This method returns the MapBuilder specified in the name
      * parameter.  You should pass in the full path to the class, ie:
      * org.apache.torque.util.db.map.TurbineMapBuilder.  The
@@ -1401,112 +1784,6 @@ public abstract class BasePeer
     }
 
     /**
-     * Performs a SQL <code>select</code> using a PreparedStatement.
-     * Note: this method does not handle null criteria values.
-     *
-     * @param criteria
-     * @param con
-     * @return a List of Record objects.
-     * @throws TorqueException Error performing database query.
-     */
-    public static List<Record> doPSSelect(Criteria criteria, Connection con)
-        throws TorqueException
-    {
-        List<Record> v = null;
-
-        StringBuffer qry = new StringBuffer();
-        List<Object> params = new ArrayList<Object>(criteria.size());
-
-        createPreparedStatement(criteria, qry, params);
-
-        PreparedStatement statement = null;
-        try
-        {
-            statement = con.prepareStatement(qry.toString());
-
-            for (int i = 0; i < params.size(); i++)
-            {
-                Object param = params.get(i);
-                if (param instanceof java.sql.Date)
-                {
-                    statement.setDate(i + 1, (java.sql.Date) param);
-                }
-                else if (param instanceof NumberKey)
-                {
-                    statement.setBigDecimal(i + 1,
-                        ((NumberKey) param).getBigDecimal());
-                }
-                else if (param instanceof Integer)
-                {
-                    statement.setInt(i + 1, ((Integer) param).intValue());
-                }
-                else
-                {
-                    statement.setString(i + 1, param.toString());
-                }
-            }
-
-            QueryDataSet qds = null;
-            try
-            {
-                qds = new QueryDataSet(statement.executeQuery());
-                v = getSelectResults(qds);
-            }
-            finally
-            {
-                VillageUtils.close(qds);
-            }
-        }
-        catch (DataSetException e)
-        {
-            throwTorqueException(e);
-        }
-        catch (SQLException e)
-        {
-            throwTorqueException(e);
-        }
-        finally
-        {
-            if (statement != null)
-            {
-                try
-                {
-                    statement.close();
-                }
-                catch (SQLException e)
-                {
-                    throw new TorqueException(e);
-                }
-            }
-        }
-        return v;
-    }
-
-    /**
-     * Do a Prepared Statement select according to the given criteria
-     *
-     * @param criteria
-     * @return a List of Record objects.
-     * @throws TorqueException Any exceptions caught during processing will be
-     *         rethrown wrapped into a TorqueException.
-     */
-    public static List<Record> doPSSelect(Criteria criteria) throws TorqueException
-    {
-        Connection con = Torque.getConnection(criteria.getDbName());
-        List<Record> v = null;
-
-        try
-        {
-            v = doPSSelect(criteria, con);
-        }
-        finally
-        {
-            Torque.closeConnection(con);
-        }
-        return v;
-    }
-
-    /**
      * Create a new PreparedStatement.  It builds a string representation
      * of a query and a list of PreparedStatement parameters.
      *
@@ -1655,116 +1932,46 @@ public abstract class BasePeer
     }
 
     /**
-     * Process the result of a Table list generation.
-     * This runs the statements onto the list of tables and
-     * provides a callback hook to add functionality.
-     *
-     * This method should've been in SQLBuilder, but is uses the handleMultipleRecords callback thingie..
-     *
-     * @param crit The criteria
-     * @param tables A set of Tables to run on
-     * @param con The SQL Connection to run the statements on
-     * @param pc A ProcessCallback object
+     * Checks all columns in the criteria to see whether
+     * booleanchar and booleanint columns are queried with a boolean.
+     * If yes, the query values are mapped onto values the database
+     * does understand, i.e. 0 and 1 for booleanints and N and Y for
+     * booleanchar columns.
      *
-     * @throws Exception An Error occured (should be wrapped into TorqueException)
+     * @param columnValues The value to be checked for booleanint
+     *        and booleanchar columns.
+     * @param defaultTableMap the table map to be used if the table name is
+     *        not given in a column.
+     * @throws TorqueException if the database map for the criteria cannot be
+     *         retrieved.
      */
-    private static void processTables(Criteria crit, Set<String> tables, Connection con, ProcessCallback pc)
-            throws Exception
+    public static void correctBooleans(
+            ColumnValues columnValues)
+        throws TorqueException
     {
-        String dbName = crit.getDbName();
-        DB db = Torque.getDB(dbName);
-        DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
-
-        // create the statements for the tables
-        for (String table : tables)
+        TableMap table = columnValues.getTable();
+        for (Map.Entry<String, JdbcTypedValue> entry : columnValues.entrySet())
         {
-            KeyDef kd = new KeyDef();
-            Set<String> whereClause = new HashSet<String>();
-
-            ColumnMap[] columnMaps = dbMap.getTable(table).getColumns();
-
-            for (int j = 0; j < columnMaps.length; j++)
+            String columnName = entry.getKey();
+            ColumnMap column = table.getColumn(columnName);
+            if (column != null)
             {
-                ColumnMap colMap = columnMaps[j];
-                if (colMap.isPrimaryKey())
+                JdbcTypedValue columnValue = entry.getValue();
+                if ("BOOLEANINT".equals(column.getTorqueType()))
                 {
-                    kd.addAttrib(colMap.getColumnName());
+                    columnValue.setValue(
+                            Boolean.TRUE.equals(columnValue.getValue())
+                                    ? new Integer(1)
+                                    : new Integer(0));
                 }
-
-                String key = new StringBuffer(colMap.getTableName())
-                        .append('.')
-                        .append(colMap.getColumnName())
-                        .toString();
-
-                if (crit.containsKey(key))
+                else if ("BOOLEANCHAR".equals(column.getTorqueType()))
                 {
-                    if (crit
-                            .getComparison(key)
-                            .equals(Criteria.CUSTOM))
-                    {
-                        whereClause.add(crit.getString(key));
-                    }
-                    else
-                    {
-                        whereClause.add(
-                                SqlExpression.build(
-                                        colMap.getColumnName(),
-                                        crit.getValue(key),
-                                        crit.getComparison(key),
-                                        crit.isIgnoreCase(),
-                                        db));
-                    }
-                }
-            }
-
-            // Execute the statement for each table
-            TableDataSet tds = null;
-            try
-            {
-                String tableName = SQLBuilder.getFullTableName(table, dbName);
-
-                // Get affected records.
-                tds = new TableDataSet(con, tableName, kd);
-                String sqlSnippet = StringUtils.join(whereClause.iterator(), " AND ");
-
-                if (log.isDebugEnabled())
-                {
-                    log.debug("BasePeer: whereClause=" + sqlSnippet);
-                }
-
-                tds.where(sqlSnippet);
-                tds.fetchRecords();
-
-                if (tds.size() > 1 && crit.isSingleRecord())
-                {
-                    handleMultipleRecords(tds);
-                }
-
-                for (int j = 0; j < tds.size(); j++)
-                {
-                    Record rec = tds.getRecord(j);
-
-                    if (pc != null)
-                    {
-                        // Table name _without_ schema!
-                        pc.process(table, dbName, rec);
-                    }
-                }
-            }
-            finally
-            {
-                VillageUtils.close(tds);
+                    columnValue.setValue(
+                            Boolean.TRUE.equals(columnValue.getValue())
+                                    ? "Y"
+                                    : "N");
+                 }
             }
         }
     }
-
-    /**
-     * Inner Interface that defines the Callback method for
-     * the Record Processing
-     */
-    protected interface ProcessCallback
-    {
-        void process (String table, String dbName, Record rec)
-                throws Exception;
-    }
 }



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


Mime
View raw message