package org.apache.torque.util;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.Serializable;
import java.math.BigDecimal;
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.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.torque.Column;
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.Adapter;
import org.apache.torque.adapter.IDMethod;
import org.apache.torque.criteria.FromElement;
import org.apache.torque.map.ColumnMap;
import org.apache.torque.map.MapHelper;
import org.apache.torque.map.TableMap;
import org.apache.torque.oid.IdGenerator;
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 org.apache.torque.om.mapper.RecordMapper;
import org.apache.torque.sql.Query;
import org.apache.torque.sql.SqlBuilder;
/**
* This is the base class for all Peer classes in the system. Peer
* classes are responsible for isolating all of the database access
* for a specific business object. They execute all of the SQL
* against the database. Over time this class has grown to include
* utility methods which ease execution of cross-database queries and
* the implementation of concrete Peers.
*
* @param <T> The data object class for this Peer.
*
* @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
* @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
* @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
* @author <a href="mailto:stephenh@chase3000.com">Stephen Haberman</a>
* @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
* @author <a href="mailto:vido@ldh.org">Augustin Vidovic</a>
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @version $Id: BasePeerImpl.java 1415362 2012-11-29 20:33:52Z tfischer $
*/
public class BasePeerImpl<T> implements Serializable
{
/**
* Serial Version
*/
private static final long serialVersionUID = -7702123730779032381L;
/** the log */
private static final Log log = LogFactory.getLog(BasePeerImpl.class);
/** An injected instance of a record mapper to map JDBC result sets to objects */
private RecordMapper<T> recordMapper = null;
/** An injected instance of a table map */
private TableMap tableMap = null;
/** An injected instance of the database name */
private String databaseName = null;
/**
* Default constructor
*/
public BasePeerImpl()
{
super();
}
/**
* Constructor providing the objects to be injected as parameters.
*
* @param recordMapper a record mapper to map JDBC result sets to objects
* @param tableMap the default table map
* @param databaseName the name of the database
*/
public BasePeerImpl(RecordMapper<T> recordMapper, TableMap tableMap, String databaseName)
{
this();
setRecordMapper(recordMapper);
setTableMap(tableMap);
setDatabaseName(databaseName);
}
/**
* Set the record mapper for this instance.
*
* @param recordMapper the recordMapper to set
*/
public void setRecordMapper(RecordMapper<T> recordMapper)
{
this.recordMapper = recordMapper;
}
/**
* Get the record mapper for this instance.
*
* @return the recordMapper
*/
public RecordMapper<T> getRecordMapper() throws TorqueException
{
if (recordMapper == null)
{
throw new TorqueException("No record mapper injected");
}
return recordMapper;
}
/**
* Set the default table map for this instance.
*
* @param tableMap the tableMap to set
*/
public void setTableMap(TableMap tableMap)
{
this.tableMap = tableMap;
}
/**
* Get the default table map for this instance.
*
* @return the tableMap
*/
public TableMap getTableMap() throws TorqueException
{
if (tableMap == null)
{
throw new TorqueException("No table map injected");
}
return tableMap;
}
/**
* Set the database name for this instance.
*
* @param databaseName the databaseName to set
*/
public void setDatabaseName(String databaseName)
{
this.databaseName = databaseName;
}
/**
* Get the database name for this instance.
*
* @return the databaseName
*/
public String getDatabaseName() throws TorqueException
{
if (databaseName == null)
{
throw new TorqueException("No database name injected");
}
return databaseName;
}
/**
* Convenience method to create a String array of criteria keys.
*
* @param tableName Name of table.
* @param columnNames A String[].
* @return A String[].
*
* @deprecated This method is not used any more and will be removed in a
* future version of Torque.
*/
@Deprecated
public String[] initCriteriaKeys(
String tableName,
String[] columnNames)
{
String[] keys = new String[columnNames.length];
for (int i = 0; i < columnNames.length; i++)
{
keys[i] = tableName + "." + columnNames[i].toUpperCase();
}
return keys;
}
/**
* Convenience method that uses straight JDBC to delete multiple
* rows.
*
* @param con A Connection.
* @param table The table to delete records from.
* @param column The column in the where clause.
* @param value The value of the column.
*
* @return the number of deleted rows.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*
* @deprecated The value is not SQL escaped.
* Better use doDelete(Criteria, String, Connection)
* for automatic escaping and more flexibility.
* This method will be removed in a future version of Torque.
*/
@Deprecated
public int deleteAll(
Connection con,
String table,
String column,
int value)
throws TorqueException
{
Statement statement = null;
try
{
statement = con.createStatement();
StringBuffer query = new StringBuffer();
query.append("DELETE FROM ")
.append(table)
.append(" WHERE ")
.append(column)
.append(" = ")
.append(value);
return statement.executeUpdate(query.toString());
}
catch (SQLException e)
{
throw new TorqueException(e);
}
finally
{
if (statement != null)
{
try
{
statement.close();
}
catch (SQLException e)
{
throw new TorqueException(e);
}
}
}
}
/**
* Convenience method that uses straight JDBC to delete multiple
* rows. This method attempts to get the default database from
* the pool.
*
* @param table The table to delete records from.
* @param column The column in the where clause.
* @param value The value of the column.
*
* @return the number of deleted rows.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*
* @deprecated The value is not SQL escaped.
* Better use doDelete(Criteria, String)
* for automatic escaping and more flexibility.
* This method will be removed in a future version of Torque.
*/
@Deprecated
public int deleteAll(String table, String column, int value)
throws TorqueException
{
Connection con = null;
try
{
con = Transaction.begin(Torque.getDefaultDB());
int result = deleteAll(con, table, column, value);
Transaction.commit(con);
con = null;
return result;
}
finally
{
if (con != null)
{
Transaction.safeRollback(con);
}
}
}
/**
* Deletes rows from a database table.
*
* @param criteria defines the rows to be deleted, not null.
*
* @return the number of deleted rows.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
public int doDelete(org.apache.torque.criteria.Criteria criteria)
throws TorqueException
{
Connection connection = null;
try
{
setDbName(criteria);
connection = Transaction.begin(criteria.getDbName());
int deletedRows = doDelete(criteria, connection);
Transaction.commit(connection);
connection = null;
return deletedRows;
}
finally
{
if (connection != null)
{
Transaction.safeRollback(connection);
}
}
}
/**
* Deletes rows from a table. This method is to be used
* during a transaction, otherwise use the doDelete(Criteria) method.
*
* @param criteria defines the rows to be deleted, not null.
* @param connection the connection to use, not null.
*
* @return the number of deleted rows.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
public int doDelete(
org.apache.torque.criteria.Criteria criteria,
Connection connection)
throws TorqueException
{
correctBooleans(criteria);
setDbName(criteria);
Query query = SqlBuilder.buildQuery(criteria);
query.setType(Query.Type.DELETE);
String fullTableName;
if (tableMap == null)
{
fullTableName = SqlBuilder.guessFullTableFromCriteria(criteria);
}
else
{
fullTableName = SqlBuilder.getFullTableName(
tableMap.getFullyQualifiedTableName(),
criteria.getDbName());
}
boolean ownTableAdded = false;
for (FromElement fromElement : query.getFromClause())
{
// Table names are case insensitive in known databases
// so use case-insensitive compare
if (fullTableName.equalsIgnoreCase(fromElement.getFromExpression()))
{
ownTableAdded = true;
break;
}
}
if (!ownTableAdded)
{
query.getFromClause().add(new FromElement(fullTableName));
}
String sql = query.toString();
PreparedStatement preparedStatement = null;
try
{
preparedStatement = connection.prepareStatement(sql);
List<Object> replacements = setPreparedStatementReplacements(
preparedStatement,
query.getPreparedStatementReplacements(),
0);
long startTime = System.currentTimeMillis();
log.debug("Executing delete " + sql
+ ", parameters = "
+ replacements);
int affectedRows = preparedStatement.executeUpdate();
long queryEndTime = System.currentTimeMillis();
log.trace("delete took " + (queryEndTime - startTime)
+ " milliseconds");
preparedStatement.close();
preparedStatement = null;
return affectedRows;
}
catch (SQLException e)
{
throw ExceptionMapper.getInstance().toTorqueException(e);
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
log.warn("error closing prepared statement", e);
}
}
}
}
/**
* Method to perform deletes based on conditions in a Criteria.
*
* @param criteria The criteria to use.
*
* @return the number of deleted rows.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*
* @deprecated This method causes unexpected results when joins are used.
* Please use doDelete(
* org.apache.torque.criteria.Criteria, TableMap).
* This method will be removed in a future version of Torque.
*/
@Deprecated
protected int doDelete(Criteria criteria) throws TorqueException
{
Connection con = null;
try
{
con = Transaction.begin(criteria.getDbName());
int result = doDelete(criteria, con);
Transaction.commit(con);
con = null;
return result;
}
finally
{
if (con != null)
{
Transaction.safeRollback(con);
}
}
}
/**
* Method to perform deletes based on conditions a Criteria.
*
* @param criteria The criteria to use.
* @param con the Connection to be used for deleting.
*
* @return the number of deleted rows.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*
* @deprecated This method causes unexpected results when joins are used.
* Please use doDelete(
* org.apache.torque.criteria.Criteria, TableMap, Connection).
* This method will be removed in a future version of Torque.
*/
@Deprecated
protected int doDelete(Criteria criteria, Connection con)
throws TorqueException
{
if (criteria.values().isEmpty())
{
throw new TorqueException("No conditions found in Criteria");
}
Criteria.Criterion criterion
= criteria.values().iterator().next();
TableMap tableMapFromCriteria = MapHelper.getTableMap(
criterion.getColumn(), criteria, null);
if (tableMapFromCriteria == null)
{
throw new TorqueException("Unqualified column name in criteria"
+ " or table name not found in database map");
}
Query query = SqlBuilder.buildQuery(criteria);
query.setType(Query.Type.DELETE);
String fullTableName = null;
if (tableMap != null)
{
fullTableName = SqlBuilder.getFullTableName(
tableMap.getFullyQualifiedTableName(),
criteria.getDbName());
}
else
{
Column column = criteria.values().iterator().next().getColumn();
fullTableName = SqlBuilder.getFullTableName(
column.getFullTableName(),
criteria.getDbName());
}
boolean ownTableAdded = false;
for (FromElement fromElement : query.getFromClause())
{
// Table names are case insensitive in known databases
// so use case-insensitive compare
if (fullTableName.equalsIgnoreCase(fromElement.getFromExpression()))
{
ownTableAdded = true;
break;
}
}
if (!ownTableAdded)
{
query.getFromClause().add(new FromElement(fullTableName));
}
String sql = query.toString();
PreparedStatement preparedStatement = null;
try
{
preparedStatement = con.prepareStatement(sql);
List<Object> replacements = setPreparedStatementReplacements(
preparedStatement,
query.getPreparedStatementReplacements(),
0);
long startTime = System.currentTimeMillis();
log.debug("Executing delete " + sql
+ ", parameters = "
+ replacements);
int affectedRows = preparedStatement.executeUpdate();
long queryEndTime = System.currentTimeMillis();
log.trace("delete took " + (queryEndTime - startTime)
+ " milliseconds");
preparedStatement.close();
preparedStatement = null;
return affectedRows;
}
catch (SQLException e)
{
throw ExceptionMapper.getInstance().toTorqueException(e);
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
log.warn("error closing prepared statement", e);
}
}
}
}
/**
* Inserts a record into a database table.
* <p>
* If the primary key is included in Criteria, then that value will
* be used to insert the row.
* <p>
* 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 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.
*
* @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 ObjectKey doInsert(ColumnValues insertValues)
throws TorqueException
{
String databaseNameFromInsertValues = insertValues.getDbName();
if (databaseNameFromInsertValues == null)
{
databaseNameFromInsertValues = getDatabaseName();
}
Connection connection = null;
try
{
connection = Transaction.begin(databaseNameFromInsertValues);
ObjectKey id = doInsert(insertValues, connection);
Transaction.commit(connection);
connection = null;
return id;
}
finally
{
if (connection != null)
{
Transaction.safeRollback(connection);
}
}
}
/**
* Inserts a record into a database table.
* <p>
* If the primary key is included in Criteria, then that value will
* be used to insert the row.
* <p>
* 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 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 ObjectKey doInsert(
ColumnValues insertValues,
Connection connection)
throws TorqueException
{
if (insertValues == null)
{
throw new TorqueException("insertValues is null");
}
if (connection == null)
{
throw new TorqueException("connection is null");
}
String databaseNameFromInsertValues = insertValues.getDbName();
if (databaseNameFromInsertValues == null)
{
databaseNameFromInsertValues = getDatabaseName();
}
Database database = Torque.getDatabase(databaseNameFromInsertValues);
Object keyInfo = getIdMethodInfo();
IdGenerator keyGen = database.getIdGenerator(
getTableMap().getPrimaryKeyMethod());
SimpleKey id = null;
// can currently generate only single column pks, therefore a single
// columnMap is ok
ColumnMap primaryKey = null;
if (keyGen != null)
{
// fail on multiple pks
primaryKey = getTableMap().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))
{
id = getId(primaryKey, keyGen, connection, keyInfo);
insertValues.put(
primaryKey,
new JdbcTypedValue(id.getValue(), id.getJdbcType()));
}
}
List<String> columnNames = new ArrayList<String>();
List<JdbcTypedValue> replacementObjects
= new ArrayList<JdbcTypedValue>();
for (Map.Entry<Column, JdbcTypedValue> columnValue
: insertValues.entrySet())
{
Column column = columnValue.getKey();
columnNames.add(column.getColumnName());
JdbcTypedValue value = columnValue.getValue();
replacementObjects.add(value);
}
String fullTableName = SqlBuilder.getFullTableName(
getTableMap().getFullyQualifiedTableName(),
databaseNameFromInsertValues);
StringBuilder query = new StringBuilder("INSERT INTO ")
.append(fullTableName)
.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 = 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 (SQLException e)
{
throw ExceptionMapper.getInstance().toTorqueException(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()
&& primaryKey != null
&& !insertValues.containsKey(
primaryKey))
{
id = getId(primaryKey, keyGen, connection, keyInfo);
}
return id;
}
/**
* Returns the idMethodInfo for the table for this Peer class.
*
* @return the idMethodInfo, not null.
*
* @throws TorqueException if the database adapter for the table's database
* needs to be accessed but is not configured.
*/
private Object getIdMethodInfo()
throws TorqueException
{
IDMethod idMethod = tableMap.getPrimaryKeyMethod();
if (IDMethod.NATIVE == idMethod)
{
Adapter adapter = Torque.getAdapter(getDatabaseName());
if (adapter == null)
{
throw new TorqueException(
"missing adapter configuration for database "
+ getDatabaseName()
+ "check the Torque configuration");
}
idMethod = adapter.getIDMethodType();
}
Object keyInfo = tableMap.getPrimaryKeyMethodInfo(idMethod);
return keyInfo;
}
/**
* Create an Id for insertion in the Criteria
*
* @param pk ColumnMap for the Primary key
* @param keyGen The Id Generator object
* @param con The SQL Connection to run the id generation under
* @param keyInfo KeyInfo Parameter from the Table map
*
* @return A simple Key representing the new Id value
* @throws TorqueException Possible errors get wrapped in here.
*/
private SimpleKey getId(
ColumnMap pk,
IdGenerator keyGen,
Connection con,
Object keyInfo)
throws TorqueException
{
SimpleKey id = null;
if (pk != null && keyGen != null)
{
if (pk.getType() instanceof Number)
{
id = new NumberKey(
keyGen.getIdAsBigDecimal(con, keyInfo));
}
else
{
id = new StringKey(keyGen.getIdAsString(con, keyInfo));
}
}
return id;
}
/**
* Add all the columns needed to create a new object.
*
* @param criteria the Criteria to which the select columns should
* be added.
*/
public void addSelectColumns(org.apache.torque.criteria.Criteria criteria)
{
ColumnMap[] columns = this.tableMap.getColumns();
for (ColumnMap c : columns)
{
criteria.addSelectColumn(c);
}
}
/**
* Add all the columns needed to create a new object.
*
* @param criteria the Criteria to which the select columns should
* be added.
*
* @deprecated Please use addSelectColumns(
* org.apache.torque.criteria.Criteria).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public void addSelectColumns(Criteria criteria)
{
ColumnMap[] columns = this.tableMap.getColumns();
for (ColumnMap c : columns)
{
criteria.addSelectColumn(c);
}
}
/**
* Selects objects from a database.
*
* @param criteria object used to create the SELECT statement.
*
* @return the list of selected objects, not null.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*
* @deprecated Please use doSelect(org.apache.torque.criteria.Criteria).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public List<T> doSelect(Criteria criteria)
throws TorqueException
{
if (criteria.getSelectColumns().size() == 0)
{
addSelectColumns(criteria);
}
setDbName(criteria);
return doSelect(
criteria,
getRecordMapper());
}
/**
* Selects objects from a database.
*
* @param criteria object used to create the SELECT statement.
*
* @return the list of selected objects, not null.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
public List<T> doSelect(org.apache.torque.criteria.Criteria criteria)
throws TorqueException
{
if (criteria.getSelectColumns().size() == 0)
{
addSelectColumns(criteria);
}
setDbName(criteria);
return doSelect(
criteria,
getRecordMapper());
}
/**
* Selects objects from a database
* within a transaction.
*
* @param criteria object used to create the SELECT statement.
* @param connection the connection to use, not null.
*
* @return the list of selected objects, not null.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*
* @deprecated Please use doSelect(org.apache.torque.criteria.Criteria,
* Connection).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public List<T> doSelect(
Criteria criteria,
Connection connection)
throws TorqueException
{
if (criteria.getSelectColumns().size() == 0)
{
addSelectColumns(criteria);
}
setDbName(criteria);
return doSelect(
criteria,
getRecordMapper(),
connection);
}
/**
* Selects objects from a database
* within a transaction.
*
* @param criteria object used to create the SELECT statement.
* @param connection the connection to use, not null.
*
* @return the list of selected objects, not null.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
public List<T> doSelect(
org.apache.torque.criteria.Criteria criteria,
Connection connection)
throws TorqueException
{
if (criteria.getSelectColumns().size() == 0)
{
addSelectColumns(criteria);
}
setDbName(criteria);
return doSelect(
criteria,
getRecordMapper(),
connection);
}
/**
* Selects at most one object from a database.
*
* @param criteria object used to create the SELECT statement.
*
* @return the selected Object, or null if no object was selected.
*
* @throws TorqueException If more than one record is selected or if
* an error occurs when processing the query.
*/
public T doSelectSingleRecord(org.apache.torque.criteria.Criteria criteria)
throws TorqueException
{
List<T> recordList = doSelect(criteria);
T record = null;
if (recordList.size() > 1)
{
throw new TooManyRowsException("Criteria " + criteria
+ " matched more than one record");
}
if (!recordList.isEmpty())
{
record = recordList.get(0);
}
return record;
}
/**
* Selects at most one object from a database
* within a transaction.
*
* @param criteria object used to create the SELECT statement.
* @param connection the connection holding the transaction, not null.
*
* @return the selected Object, or null if no object was selected.
*
* @throws TorqueException If more than one record is selected or if
* an error occurs when processing the query.
*/
public T doSelectSingleRecord(
org.apache.torque.criteria.Criteria criteria,
Connection connection)
throws TorqueException
{
List<T> recordList = doSelect(criteria, connection);
T record = null;
if (recordList.size() > 1)
{
throw new TooManyRowsException("Criteria " + criteria
+ " matched more than one record");
}
if (!recordList.isEmpty())
{
record = recordList.get(0);
}
return record;
}
/**
* Selects rows from a database an maps them to objects.
*
* @param criteria A Criteria specifying the records to select, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
*
* @return The results of the query, not null.
*
* @throws TorqueException if querying the database fails.
*
* @deprecated Please use doSelect(org.apache.torque.criteria.Criteria,
* RecordMapper).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public <TT> List<TT> doSelect(
Criteria criteria,
RecordMapper<TT> mapper)
throws TorqueException
{
Connection connection = null;
try
{
connection = Transaction.begin(criteria.getDbName());
List<TT> result = doSelect(
criteria,
mapper,
connection);
Transaction.commit(connection);
connection = null;
return result;
}
finally
{
if (connection != null)
{
Transaction.safeRollback(connection);
}
}
}
/**
* Selects rows from a database an maps them to objects.
*
* @param criteria A Criteria specifying the records to select, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
*
* @return The results of the query, not null.
*
* @throws TorqueException if querying the database fails.
*/
public <TT> List<TT> doSelect(
org.apache.torque.criteria.Criteria criteria,
RecordMapper<TT> mapper)
throws TorqueException
{
Connection connection = null;
try
{
connection = Transaction.begin(criteria.getDbName());
List<TT> result = doSelect(
criteria,
mapper,
connection);
Transaction.commit(connection);
connection = null;
return result;
}
finally
{
if (connection != null)
{
Transaction.safeRollback(connection);
}
}
}
/**
* Selects rows from a database an maps them to objects.
*
* @param query the sql query to execute, not null.
*
* @return The results of the query, not null.
*
* @throws TorqueException if querying the database fails.
*/
public List<T> doSelect(String query)
throws TorqueException
{
return doSelect(
query,
getRecordMapper(),
getDatabaseName());
}
/**
* Selects rows from a database an maps them to objects.
*
* @param query the SQL Query to execute, not null.
* @param connection the database connection, not null.
*
* @return The results of the query, not null.
*
* @throws TorqueException if querying the database fails.
*/
public List<T> doSelect(
String query,
Connection connection)
throws TorqueException
{
return doSelect(
query,
getRecordMapper(),
connection);
}
/**
* Selects rows from a database an maps them to objects.
*
* @param query the sql query to execute, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
* @param dbName The name of the database to create the connection for,
* or null for the default DB.
*
* @return The results of the query, not null.
*
* @throws TorqueException if querying the database fails.
*/
public <TT> List<TT> doSelect(
String query,
RecordMapper<TT> mapper,
String dbName)
throws TorqueException
{
Connection connection = null;
try
{
connection = Transaction.begin((dbName == null)
? Torque.getDefaultDB()
: dbName);
List<TT> result = doSelect(
query,
mapper,
connection);
Transaction.commit(connection);
connection = null;
return result;
}
finally
{
if (connection != null)
{
Transaction.safeRollback(connection);
}
}
}
/**
* Selects rows from a database an maps them to objects.
*
* @param query the SQL Query to execute, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
* @param connection the database connection, not null.
*
* @return The results of the query, not null.
*
* @throws TorqueException if querying the database fails.
*/
public <TT> List<TT> doSelect(
String query,
RecordMapper<TT> mapper,
Connection connection)
throws TorqueException
{
if (connection == null)
{
throw new NullPointerException("connection is null");
}
List<TT> result = new ArrayList<TT>();
Statement statement = null;
ResultSet resultSet = null;
try
{
statement = connection.createStatement();
long startTime = System.currentTimeMillis();
log.debug("Executing query " + query);
resultSet = statement.executeQuery(query.toString());
long queryEndTime = System.currentTimeMillis();
log.trace("query took " + (queryEndTime - startTime)
+ " milliseconds");
while (resultSet.next())
{
TT rowResult = mapper.processRow(resultSet, 0, null);
result.add(rowResult);
}
long mappingEndTime = System.currentTimeMillis();
log.trace("mapping took " + (mappingEndTime - queryEndTime)
+ " milliseconds");
}
catch (SQLException e)
{
throw ExceptionMapper.getInstance().toTorqueException(e);
}
finally
{
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 result;
}
/**
* Performs a SQL <code>select</code> using a PreparedStatement.
*
* @param criteria A Criteria specifying the records to select, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
* @param connection the database connection for selecting records,
* not null.
*
* @return The results of the query, not null.
*
* @throws TorqueException Error performing database query.
*
* @deprecated Please use doSelect(org.apache.torque.criteria.Criteria,
* RecordMapper, Connection).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public <TT> List<TT> doSelect(
Criteria criteria,
RecordMapper<TT> mapper,
Connection connection)
throws TorqueException
{
correctBooleans(criteria);
Query query = SqlBuilder.buildQuery(criteria);
if (query.getFromClause().isEmpty())
{
String tableName = SqlBuilder.getFullTableName(
getTableMap().getFullyQualifiedTableName(),
criteria.getDbName());
query.getFromClause().add(new FromElement(tableName));
}
PreparedStatement statement = null;
ResultSet resultSet = null;
try
{
statement = connection.prepareStatement(query.toString());
List<Object> replacements = setPreparedStatementReplacements(
statement,
query.getPreparedStatementReplacements(),
0);
long startTime = System.currentTimeMillis();
log.debug("Executing query " + query
+ ", parameters = "
+ replacements);
resultSet = statement.executeQuery();
long queryEndTime = System.currentTimeMillis();
log.trace("query took " + (queryEndTime - startTime)
+ " milliseconds");
long offset;
Database database = Torque.getDatabase(criteria.getDbName());
if (database.getAdapter().supportsNativeOffset())
{
offset = 0; //database takes care of offset
}
else
{
offset = criteria.getOffset();
}
long 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<TT> result = new ArrayList<TT>();
int rowNumber = 0;
while (resultSet.next())
{
if (rowNumber < offset)
{
rowNumber++;
continue;
}
if (limit >= 0 && rowNumber >= limit)
{
break;
}
TT rowResult = mapper.processRow(resultSet, 0, criteria);
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)
{
throw ExceptionMapper.getInstance().toTorqueException(e);
}
finally
{
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);
}
}
}
}
/**
* Performs a SQL <code>select</code> using a PreparedStatement.
*
* @param criteria A Criteria specifying the records to select, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
* @param connection the database connection for selecting records,
* not null.
*
* @return The results of the query, not null.
*
* @throws TorqueException Error performing database query.
*/
public <TT> List<TT> doSelect(
org.apache.torque.criteria.Criteria criteria,
RecordMapper<TT> mapper,
Connection connection)
throws TorqueException
{
correctBooleans(criteria);
Query query = SqlBuilder.buildQuery(criteria);
if (query.getFromClause().isEmpty())
{
String tableName = SqlBuilder.getFullTableName(
getTableMap().getFullyQualifiedTableName(),
criteria.getDbName());
query.getFromClause().add(new FromElement(tableName));
}
PreparedStatement statement = null;
ResultSet resultSet = null;
try
{
statement = connection.prepareStatement(query.toString());
if (query.getFetchSize() != null)
{
statement.setFetchSize(query.getFetchSize());
}
List<Object> replacements = setPreparedStatementReplacements(
statement,
query.getPreparedStatementReplacements(),
0);
long startTime = System.currentTimeMillis();
log.debug("Executing query " + query
+ ", parameters = "
+ replacements);
resultSet = statement.executeQuery();
long queryEndTime = System.currentTimeMillis();
log.trace("query took " + (queryEndTime - startTime)
+ " milliseconds");
long offset;
Database database = Torque.getDatabase(criteria.getDbName());
if (database.getAdapter().supportsNativeOffset())
{
offset = 0; //database takes care of offset
}
else
{
offset = criteria.getOffset();
}
long 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<TT> result = new ArrayList<TT>();
int rowNumber = 0;
while (resultSet.next())
{
if (rowNumber < offset)
{
rowNumber++;
continue;
}
if (limit >= 0 && rowNumber >= limit)
{
break;
}
TT rowResult = mapper.processRow(resultSet, 0, criteria);
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)
{
throw ExceptionMapper.getInstance().toTorqueException(e);
}
finally
{
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);
}
}
}
}
/**
* Selects at most a single row from a database an maps them to objects.
*
* @param criteria A Criteria specifying the records to select, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
*
* @return The selected row, or null if no records was selected.
*
* @throws TorqueException if querying the database fails.
*/
public <TT> TT doSelectSingleRecord(
org.apache.torque.criteria.Criteria criteria,
RecordMapper<TT> mapper)
throws TorqueException
{
List<TT> resultList = doSelect(criteria, mapper);
TT result = null;
if (resultList.size() > 1)
{
throw new TooManyRowsException("Criteria " + criteria
+ " matched more than one record");
}
if (!resultList.isEmpty())
{
result = resultList.get(0);
}
return result;
}
/**
* Selects at most a single row from a database an maps them to objects.
*
* @param criteria A Criteria specifying the records to select, not null.
* @param mapper The mapper creating the objects from the resultSet,
* not null.
* @param connection the database connection, not null.
*
* @return The selected row, or null if no records was selected.
*
* @throws TorqueException if querying the database fails.
*/
public <TT> TT doSelectSingleRecord(
org.apache.torque.criteria.Criteria criteria,
RecordMapper<TT> mapper,
Connection connection)
throws TorqueException
{
List<TT> resultList = doSelect(
criteria,
mapper,
connection);
TT result = null;
if (resultList.size() > 1)
{
throw new TooManyRowsException("Criteria " + criteria
+ " matched more than one record");
}
if (!resultList.isEmpty())
{
result = resultList.get(0);
}
return result;
}
/**
* Convenience method used to update rows in the DB. Checks if a
* <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 = someValue"
* <p>
* 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.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
public int doUpdate(ColumnValues updateValues)
throws TorqueException
{
String databaseNameFromUpdateValues = updateValues.getDbName();
if (databaseNameFromUpdateValues == null)
{
databaseNameFromUpdateValues = getDatabaseName();
}
Connection connection = null;
try
{
connection = Transaction.begin(databaseNameFromUpdateValues);
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> 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 = someValue"
* <p>
* 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.
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
public int doUpdate(
ColumnValues updateValues,
Connection connection)
throws TorqueException
{
ColumnMap pk = getTableMap().getPrimaryKey();
org.apache.torque.criteria.Criteria selectCriteria = null;
if (pk != null && updateValues.containsKey(pk.getSqlExpression()))
{
selectCriteria = new org.apache.torque.criteria.Criteria();
selectCriteria.where(pk,
updateValues.remove(pk.getSqlExpression()));
}
else
{
throw new TorqueException("No PK specified for database update");
}
return doUpdate(selectCriteria, updateValues, connection);
}
/**
* 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 selects which rows of which table
* should be updated, not null.
* @param updateValues Which columns to update with which values, not null.
*
* @return the number of affected rows.
*
* @throws TorqueException if updating fails.
*
* @deprecated Please use doUpdate(
* org.apache.torque.criteria.Criteria, ColumnValues).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public int doUpdate(
Criteria selectCriteria,
ColumnValues updateValues)
throws TorqueException
{
String databaseNameFromUpdateValues = updateValues.getDbName();
if (databaseNameFromUpdateValues == null)
{
databaseNameFromUpdateValues = getDatabaseName();
}
Connection connection = null;
try
{
connection = Transaction.begin(databaseNameFromUpdateValues);
int result = doUpdate(selectCriteria, updateValues, connection);
Transaction.commit(connection);
connection = null;
return result;
}
finally
{
if (connection != null)
{
Transaction.safeRollback(connection);
}
}
}
/**
* 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 selects which rows of which table
* should be updated, not null.
* @param updateValues Which columns to update with which values, not null.
*
* @return the number of affected rows.
*
* @throws TorqueException if updating fails.
*/
public int doUpdate(
org.apache.torque.criteria.Criteria selectCriteria,
ColumnValues updateValues)
throws TorqueException
{
String databaseNameFromUpdateValues = updateValues.getDbName();
if (databaseNameFromUpdateValues == null)
{
databaseNameFromUpdateValues = getDatabaseName();
}
Connection connection = null;
try
{
connection = Transaction.begin(databaseNameFromUpdateValues);
int result = doUpdate(selectCriteria, updateValues, connection);
Transaction.commit(connection);
connection = null;
return result;
}
finally
{
if (connection != null)
{
Transaction.safeRollback(connection);
}
}
}
/**
* 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 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.
*
* @deprecated Please use doUpdate(org.apache.torque.criteria.Criteria,
* ColumnValues, Connection).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public int doUpdate(
Criteria criteria,
ColumnValues updateValues,
Connection connection)
throws TorqueException
{
Query query = SqlBuilder.buildQuery(criteria);
query.setType(Query.Type.UPDATE);
query.getFromClause().clear();
String fullTableName = SqlBuilder.getFullTableName(
getTableMap().getFullyQualifiedTableName(),
criteria.getDbName());
query.getFromClause().add(new FromElement(fullTableName));
List<JdbcTypedValue> replacementObjects
= new ArrayList<JdbcTypedValue>();
for (Map.Entry<Column, JdbcTypedValue> updateValue
: updateValues.entrySet())
{
Column column = updateValue.getKey();
query.getSelectClause().add(column.getColumnName());
replacementObjects.add(updateValue.getValue());
}
PreparedStatement preparedStatement = null;
try
{
preparedStatement = connection.prepareStatement(query.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++;
}
List<Object> replacements = setPreparedStatementReplacements(
preparedStatement,
query.getPreparedStatementReplacements(),
position - 1);
long startTime = System.currentTimeMillis();
log.debug("Executing update " + query.toString()
+ " using update parameters " + replacementObjects
+ " and query parameters "
+ replacements);
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 ExceptionMapper.getInstance().toTorqueException(e);
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
log.warn("error closing prepared statement", 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 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 int doUpdate(
org.apache.torque.criteria.Criteria criteria,
ColumnValues updateValues,
Connection connection)
throws TorqueException
{
Query query = SqlBuilder.buildQuery(criteria);
query.setType(Query.Type.UPDATE);
query.getFromClause().clear();
String fullTableName = SqlBuilder.getFullTableName(
getTableMap().getFullyQualifiedTableName(),
criteria.getDbName());
query.getFromClause().add(new FromElement(fullTableName));
List<JdbcTypedValue> replacementObjects
= new ArrayList<JdbcTypedValue>();
for (Map.Entry<Column, JdbcTypedValue> updateValue
: updateValues.entrySet())
{
Column column = updateValue.getKey();
query.getSelectClause().add(column.getColumnName());
replacementObjects.add(updateValue.getValue());
}
PreparedStatement preparedStatement = null;
try
{
preparedStatement = connection.prepareStatement(query.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++;
}
List<Object> replacements = setPreparedStatementReplacements(
preparedStatement,
query.getPreparedStatementReplacements(),
position - 1);
long startTime = System.currentTimeMillis();
log.debug("Executing update " + query.toString()
+ " using update parameters " + replacementObjects
+ " and query parameters "
+ replacements);
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 ExceptionMapper.getInstance().toTorqueException(e);
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
log.warn("error closing prepared statement", e);
}
}
}
}
/**
* Utility method which executes a given sql statement
* as prepared statement.
* This method should be used for update, insert, and delete statements.
* Use executeQuery() for selects.
*
* @param statementString A String with the sql statement to execute.
*
* @return The number of rows affected.
*
* @throws TorqueException if executing the statement fails
* or no database connection can be established.
*/
public int executeStatement(String statementString) throws TorqueException
{
return executeStatement(statementString, Torque.getDefaultDB(), null);
}
/**
* Utility method which executes a given sql statement
* as prepared statement.
* This method should be used for update, insert, and delete statements.
* Use executeQuery() for selects.
*
* @param statementString A String with the sql statement to execute.
* @param replacementValues values to use as placeholders in the query.
* or null or empty if no placeholders need to be filled.
*
* @return The number of rows affected.
*
* @throws TorqueException if executing the statement fails
* or no database connection can be established.
*/
public int executeStatement(
String statementString,
List<JdbcTypedValue> replacementValues)
throws TorqueException
{
return executeStatement(
statementString,
Torque.getDefaultDB(),
replacementValues);
}
/**
* Utility method which executes a given sql statement
* as prepared statement.
* This method should be used for update, insert, and delete statements.
* Use executeQuery() for selects.
*
* @param statementString A String with the sql statement to execute.
* @param dbName The name of the database to execute the statement against,
* or null for the default DB.
* @param replacementValues values to use as placeholders in the query.
* or null or empty if no placeholders need to be filled.
*
* @return The number of rows affected.
*
* @throws TorqueException if executing the statement fails
* or no database connection can be established.
*/
public int executeStatement(
String statementString,
String dbName,
List<JdbcTypedValue> replacementValues)
throws TorqueException
{
Connection con = null;
try
{
con = Transaction.begin(dbName);
int rowCount = executeStatement(
statementString,
con,
replacementValues);
Transaction.commit(con);
con = null;
return rowCount;
}
finally
{
if (con != null)
{
Transaction.safeRollback(con);
}
}
}
/**
* Utility method which executes a given sql statement
* as prepared statement.
* This method should be used for update, insert, and delete statements.
* Use executeQuery() for selects.
*
* @param statementString A String with the sql statement to execute.
* @param con The database connection to use.
* @param replacementValues values to use as placeholders in the query.
* or null or empty if no placeholders need to be filled.
*
* @return The number of rows affected.
*
* @throws TorqueException if executing the statement fails.
*/
public int executeStatement(
String statementString,
Connection con,
List<JdbcTypedValue> replacementValues)
throws TorqueException
{
int rowCount = -1;
PreparedStatement statement = null;
try
{
statement = con.prepareStatement(statementString);
if (replacementValues != null)
{
int position = 1;
for (JdbcTypedValue replacementValue : replacementValues)
{
if (replacementValue.getValue() == null)
{
statement.setNull(
position,
replacementValue.getJdbcType());
}
else
{
statement.setObject(
position,
replacementValue.getValue(),
replacementValue.getJdbcType());
}
++position;
}
}
rowCount = statement.executeUpdate();
}
catch (SQLException e)
{
throw new TorqueException(e);
}
finally
{
if (statement != null)
{
try
{
statement.close();
}
catch (SQLException e)
{
throw new TorqueException(e);
}
}
}
return rowCount;
}
/**
* Sets the prepared statement replacements into a query, possibly
* modifying the type if required by DB Drivers.
*
* @param statement the statement to set the parameters in, not null.
* @param replacements the replacements to set, not null.
* @param offset the offset on the parameters, 0 for no offset.
*
* @return the parameters set.
*
* @throws SQLException if setting the parameter fails.
*/
private List<Object> setPreparedStatementReplacements(
PreparedStatement statement,
List<Object> replacements,
int offset)
throws SQLException
{
List<Object> result = new ArrayList<Object>(replacements.size());
int i = 1 + offset;
for (Object param : replacements)
{
if (param instanceof java.sql.Timestamp)
{
statement.setTimestamp(i, (java.sql.Timestamp) param);
result.add(param);
}
else if (param instanceof java.sql.Date)
{
statement.setDate(i, (java.sql.Date) param);
result.add(param);
}
else if (param instanceof java.util.Date)
{
java.sql.Timestamp sqlDate = new java.sql.Timestamp(
((java.util.Date) param).getTime());
statement.setTimestamp(i, sqlDate);
result.add(sqlDate);
}
else if (param instanceof NumberKey)
{
BigDecimal bigDecimal = ((NumberKey) param).getBigDecimal();
statement.setBigDecimal(i, bigDecimal);
result.add(bigDecimal);
}
else if (param instanceof Integer)
{
statement.setInt(i, ((Integer) param).intValue());
result.add(param);
}
else if (param instanceof Long)
{
statement.setLong(i, ((Long) param).longValue());
result.add(param);
}
else if (param instanceof BigDecimal)
{
statement.setBigDecimal(i, (BigDecimal) param);
result.add(param);
}
else if (param instanceof Boolean)
{
statement.setBoolean(i, ((Boolean) param).booleanValue());
result.add(param);
}
else
{
statement.setString(i, param.toString());
result.add(param.toString());
}
++i;
}
return result;
}
/**
* Changes the boolean values in the criteria to the appropriate type,
* whenever a booleanchar or booleanint column is involved.
* This enables the user to create criteria using Boolean values
* for booleanchar or booleanint columns.
*
* @param criteria the criteria in which the boolean values should be
* corrected.
* @throws TorqueException if the database map for the criteria cannot be
* obtained.
*
* @deprecated Please use correctBooleans(
* org.apache.torque.criteria.Criteria).
* This method will be removed in a future version of Torque.
*/
@Deprecated
public void correctBooleans(Criteria criteria)
throws TorqueException
{
for (Object criterionObject : criteria.values())
{
Criteria.Criterion criterion = (Criteria.Criterion) criterionObject;
correctBooleans(criteria, criterion);
}
}
/**
* 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.
*
* @param criteria The criteria to which teh criterion belongs.
* @param criterion The criterion to be checked for booleanint
* and booleanchar columns.
*
* @throws TorqueException if the database map for the criteria cannot be
* retrieved.
*
* @deprecated
*/
@Deprecated
private void correctBooleans(
Criteria criteria,
Criteria.Criterion criterion)
throws TorqueException
{
Column column = criterion.getColumn();
TableMap tableMapFromCriteria = MapHelper.getTableMap(
column,
criteria,
tableMap);
// if no description of table available, do not modify anything
if (tableMapFromCriteria != null)
{
String columnName = column.getColumnName();
ColumnMap columnMap = tableMapFromCriteria.getColumn(columnName);
if (columnMap != null)
{
if ("BOOLEANINT".equals(columnMap.getTorqueType()))
{
replaceBooleanValues(
criterion,
Integer.valueOf(1),
Integer.valueOf(0));
}
else if ("BOOLEANCHAR".equals(columnMap.getTorqueType()))
{
replaceBooleanValues(criterion, "Y", "N");
}
}
}
for (Criteria.Criterion attachedCriterion : criterion.getClauses())
{
correctBooleans(criteria, attachedCriterion);
}
}
/**
* 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.
*
* @param criteria The criteria to be checked for booleanint and booleanchar
* columns.
*
* @throws TorqueException if the database map for the criteria cannot be
* retrieved.
*/
public void correctBooleans(
org.apache.torque.criteria.Criteria criteria)
throws TorqueException
{
correctBooleans(
criteria,
criteria.getTopLevelCriterion());
}
private void correctBooleans(
org.apache.torque.criteria.Criteria criteria,
org.apache.torque.criteria.Criterion criterion)
throws TorqueException
{
if (criterion == null)
{
return;
}
if (criterion.isComposite())
{
for (org.apache.torque.criteria.Criterion part
: criterion.getParts())
{
correctBooleans(criteria, part);
}
return;
}
Object possibleColumn = criterion.getLValue();
TableMap tableMapForColumn = MapHelper.getTableMap(
possibleColumn,
criteria,
tableMap);
// if no description of table available, do not modify anything
if (tableMapForColumn == null)
{
return;
}
String columnName = ((Column) possibleColumn).getColumnName();
ColumnMap columnMap = tableMapForColumn.getColumn(columnName);
if (columnMap != null)
{
if ("BOOLEANINT".equals(columnMap.getTorqueType()))
{
replaceBooleanValues(
criterion,
Integer.valueOf(1),
Integer.valueOf(0));
}
else if ("BOOLEANCHAR".equals(columnMap.getTorqueType()))
{
replaceBooleanValues(criterion, "Y", "N");
}
}
}
/**
* Replaces any Boolean value in the criterion and its attached Criterions
* by trueValue if the Boolean equals <code>Boolean.TRUE</code>
* and falseValue if the Boolean equals <code>Boolean.FALSE</code>.
*
* @param criterion the criterion to replace Boolean values in.
* @param trueValue the value by which Boolean.TRUE should be replaced.
* @param falseValue the value by which Boolean.FALSE should be replaced.
*
* @deprecated
*/
@Deprecated
private void replaceBooleanValues(
Criteria.Criterion criterion,
Object trueValue,
Object falseValue)
{
// attachedCriterions also contains the criterion itself,
// so no additional treatment is needed for the criterion itself.
Criteria.Criterion[] attachedCriterions
= criterion.getAttachedCriterion();
for (int i = 0; i < attachedCriterions.length; ++i)
{
Object criterionValue
= attachedCriterions[i].getValue();
if (criterionValue instanceof Boolean)
{
Boolean booleanValue = (Boolean) criterionValue;
attachedCriterions[i].setValue(
Boolean.TRUE.equals(booleanValue)
? trueValue
: falseValue);
}
}
}
/**
* Replaces any Boolean value in the criterion and its attached Criterions
* by trueValue if the Boolean equals <code>Boolean.TRUE</code>
* and falseValue if the Boolean equals <code>Boolean.FALSE</code>.
*
* @param criterion the criterion to replace Boolean values in.
* May not be a composite criterion.
* @param trueValue the value by which Boolean.TRUE should be replaced.
* @param falseValue the value by which Boolean.FALSE should be replaced.
*/
private void replaceBooleanValues(
org.apache.torque.criteria.Criterion criterion,
Object trueValue,
Object falseValue)
{
Object rValue = criterion.getRValue();
if (rValue instanceof Boolean)
{
Boolean booleanValue = (Boolean) rValue;
criterion.setRValue(
Boolean.TRUE.equals(booleanValue)
? trueValue
: falseValue);
}
Object lValue = criterion.getLValue();
if (lValue instanceof Boolean)
{
Boolean booleanValue = (Boolean) lValue;
criterion.setLValue(
Boolean.TRUE.equals(booleanValue)
? trueValue
: falseValue);
}
}
/**
* 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.
*
* @param columnValues The value to be checked for booleanint
* and booleanchar columns.
* @throws TorqueException if the database map for the criteria cannot be
* retrieved.
*/
public void correctBooleans(
ColumnValues columnValues)
throws TorqueException
{
for (Map.Entry<Column, JdbcTypedValue> entry : columnValues.entrySet())
{
String columnName = entry.getKey().getColumnName();
ColumnMap column = getTableMap().getColumn(columnName);
if (column != null)
{
JdbcTypedValue columnValue = entry.getValue();
if ("BOOLEANINT".equals(column.getTorqueType()))
{
if (Boolean.TRUE.equals(columnValue.getValue()))
{
entry.setValue(new JdbcTypedValue(1, Types.INTEGER));
}
else if (Boolean.FALSE.equals(columnValue.getValue()))
{
entry.setValue(new JdbcTypedValue(0, Types.INTEGER));
}
else if (columnValue.getValue() == null)
{
entry.setValue(new JdbcTypedValue(null, Types.INTEGER));
}
}
else if ("BOOLEANCHAR".equals(column.getTorqueType()))
{
if (Boolean.TRUE.equals(columnValue.getValue()))
{
entry.setValue(new JdbcTypedValue("Y", Types.CHAR));
}
else if (Boolean.FALSE.equals(columnValue.getValue()))
{
entry.setValue(new JdbcTypedValue("N", Types.CHAR));
}
else if (columnValue.getValue() == null)
{
entry.setValue(new JdbcTypedValue(null, Types.CHAR));
}
}
}
}
}
/**
* Sets the database name in the passed criteria to the table's default,
* if it is not already set.
*
* @param crit the criteria to set the database name in, not null.
*/
protected void setDbName(org.apache.torque.criteria.Criteria crit)
throws TorqueException
{
if (crit.getDbName() == null)
{
crit.setDbName(getDatabaseName());
}
}
/**
* Sets the database name in the passed criteria to the table's default,
* if it is not already set.
*
* @param crit the criteria to set the database name in, not null.
*
* @deprecated Please use addSelectColumns(
* org.apache.torque.criteria.Criteria).
* This method will be removed in a future version of Torque.
*/
@Deprecated
protected void setDbName(Criteria crit) throws TorqueException
{
if (crit.getDbName() == null)
{
crit.setDbName(getDatabaseName());
}
}
}