
com.j256.ormlite.stmt.StatementExecutor Maven / Gradle / Ivy
package com.j256.ormlite.stmt;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.j256.ormlite.dao.BaseJdbcDao;
import com.j256.ormlite.dao.CloseableIterator;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.RawResults;
import com.j256.ormlite.db.DatabaseType;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.logger.Logger;
import com.j256.ormlite.logger.LoggerFactory;
import com.j256.ormlite.stmt.mapped.MappedCreate;
import com.j256.ormlite.stmt.mapped.MappedDelete;
import com.j256.ormlite.stmt.mapped.MappedDeleteCollection;
import com.j256.ormlite.stmt.mapped.MappedQueryForId;
import com.j256.ormlite.stmt.mapped.MappedRefresh;
import com.j256.ormlite.stmt.mapped.MappedUpdate;
import com.j256.ormlite.stmt.mapped.MappedUpdateId;
import com.j256.ormlite.support.JdbcTemplate;
import com.j256.ormlite.table.TableInfo;
/**
* Executes SQL statements for a particular table in a particular database. Basically a call through to various mapped
* statement methods.
*
* @param T
* The class that the code will be operating on.
* @param ID
* The class of the ID column associated with the class. The T class does not require an ID field. The class
* needs an ID parameter however so you can use Void or Object to satisfy the compiler.
* @author graywatson
*/
public class StatementExecutor {
private static Logger logger = LoggerFactory.getLogger(StatementExecutor.class);
private final DatabaseType databaseType;
private final TableInfo tableInfo;
private final Class dataClass;
private final FieldType idField;
private final MappedQueryForId mappedQueryForId;
private final PreparedQuery preparedQueryForAll;
private final MappedCreate mappedInsert;
private final MappedUpdate mappedUpdate;
private final MappedUpdateId mappedUpdateId;
private final MappedDelete mappedDelete;
private final MappedRefresh mappedRefresh;
private final static StringArrayRowMapper stringArrayRowMapper = new StringArrayRowMapper();
/**
* Provides statements for various SQL operations.
*/
public StatementExecutor(DatabaseType databaseType, TableInfo tableInfo) throws SQLException {
this.databaseType = databaseType;
this.tableInfo = tableInfo;
this.dataClass = tableInfo.getDataClass();
this.idField = tableInfo.getIdField();
this.mappedQueryForId = MappedQueryForId.build(databaseType, tableInfo);
this.preparedQueryForAll = new QueryBuilder(databaseType, tableInfo).prepareQuery();
this.mappedInsert = MappedCreate.build(databaseType, tableInfo);
this.mappedUpdate = MappedUpdate.build(databaseType, tableInfo);
this.mappedUpdateId = MappedUpdateId.build(databaseType, tableInfo);
this.mappedDelete = MappedDelete.build(databaseType, tableInfo);
this.mappedRefresh = MappedRefresh.build(databaseType, tableInfo);
}
/**
* Return the object associated with the id or null if none. This does a SQL
* select col1,col2,... from ... where ... = id type query.
*/
public T queryForId(JdbcTemplate template, ID id) throws SQLException {
if (mappedQueryForId == null) {
throw new SQLException("Cannot query-for-id with " + dataClass + " because it doesn't have an id field");
}
return mappedQueryForId.execute(template, id);
}
/**
* Return the first object that matches the {@link PreparedQuery} or null if none.
*/
public T queryForFirst(Connection connection, PreparedQuery preparedQuery) throws SQLException {
PreparedStatement stmt = null;
try {
stmt = preparedQuery.prepareSqlStatement(connection);
if (!stmt.execute()) {
throw new SQLException("Could not query for one of " + dataClass + " with warnings: "
+ stmt.getWarnings());
}
ResultSet resultSet = stmt.getResultSet();
if (resultSet.next()) {
logger.debug("query-for-first of '{}' returned at least 1 result", preparedQuery.getStatement());
return preparedQuery.mapRow(resultSet, 0);
} else {
logger.debug("query-for-first of '{}' returned at 0 results", preparedQuery.getStatement());
return null;
}
} finally {
if (stmt != null) {
stmt.close();
}
}
}
/**
* Return a list of all of the data in the table. Should be used carefully if the table is large. Consider using the
* {@link Dao#iterator} if this is the case.
*/
public List queryForAll(Connection connection) throws SQLException {
return query(connection, preparedQueryForAll);
}
/**
* Return a list of all of the data in the table that matches the {@link PreparedQuery}. Should be used carefully if
* the table is large. Consider using the {@link Dao#iterator} if this is the case.
*/
public List query(Connection connection, PreparedQuery preparedQuery) throws SQLException {
SelectIterator iterator = null;
try {
iterator = buildIterator(/* no dao specified because no removes */null, connection, preparedQuery);
List results = new ArrayList();
while (iterator.hasNextThrow()) {
results.add(iterator.nextThrow());
}
logger.debug("query of '{}' returned {} results", preparedQuery.getStatement(), results.size());
return results;
} finally {
if (iterator != null) {
iterator.close();
}
}
}
/**
* Return a list of all of the data in the table that matches the {@link PreparedQuery}. Should be used carefully if
* the table is large. Consider using the {@link Dao#iterator} if this is the case.
*/
public RawResults queryRaw(Connection connection, String query) throws SQLException {
SelectIterator iterator = null;
try {
PreparedStatement preparedStatement = connection.prepareStatement(query);
iterator =
new SelectIterator(String[].class, null, stringArrayRowMapper, preparedStatement,
null /* we don't want it to log */);
RawResultsList results = new RawResultsList(iterator.getResultSetMetaData());
while (iterator.hasNextThrow()) {
results.add(iterator.nextThrow());
}
logger.debug("query of '{}' returned {} results", query, results.size());
return results;
} finally {
if (iterator != null) {
iterator.close();
}
}
}
/**
* Create and return an {@link SelectIterator} for the class with a connection an the default mapped query for all
* statement.
*/
public SelectIterator buildIterator(BaseJdbcDao classDao, Connection connection) throws SQLException {
return buildIterator(classDao, connection, preparedQueryForAll);
}
/**
* Create and return an {@link SelectIterator} for the class with a connection and mapped statement.
*/
public SelectIterator buildIterator(BaseJdbcDao classDao, Connection connection,
PreparedQuery preparedQuery) throws SQLException {
return new SelectIterator(dataClass, classDao, preparedQuery,
preparedQuery.prepareSqlStatement(connection), preparedQuery.getStatement());
}
/**
* Return a RawResults object associated with an internal iterator that matches the query argument.
*/
public RawResults buildIterator(Connection connection, String query) throws SQLException {
return new RawResultsIterator(query, connection.prepareStatement(query));
}
/**
* Create a new entry in the database from an object.
*/
public int create(JdbcTemplate template, T data) throws SQLException {
return mappedInsert.execute(template, data);
}
/**
* Update an object in the database.
*/
public int update(JdbcTemplate template, T data) throws SQLException {
if (mappedUpdate == null) {
throw new SQLException("Cannot update " + dataClass
+ " because it doesn't have an id field defined or only has id field");
} else {
return mappedUpdate.execute(template, data);
}
}
/**
* Update an object in the database to change its id to the newId parameter.
*/
public int updateId(JdbcTemplate template, T data, ID newId) throws SQLException {
if (mappedUpdateId == null) {
throw new SQLException("Cannot update " + dataClass + " because it doesn't have an id field defined");
} else {
return mappedUpdateId.execute(template, data, newId);
}
}
/**
* Does a query for the object's Id and copies in each of the field values from the database to refresh the data
* parameter.
*/
public int refresh(JdbcTemplate template, T data) throws SQLException {
if (mappedQueryForId == null) {
throw new SQLException("Cannot refresh " + dataClass + " because it doesn't have an id field defined");
} else {
T result = mappedRefresh.execute(template, data);
if (result == null) {
return 0;
} else {
return 1;
}
}
}
/**
* Delete an object from the database.
*/
public int delete(JdbcTemplate template, T data) throws SQLException {
if (mappedDelete == null) {
throw new SQLException("Cannot delete " + dataClass + " because it doesn't have an id field defined");
} else {
return mappedDelete.execute(template, data);
}
}
/**
* Delete a collection of objects from the database.
*/
public int deleteObjects(JdbcTemplate template, Collection datas) throws SQLException {
if (idField == null) {
throw new SQLException("Cannot delete " + dataClass + " because it doesn't have an id field defined");
} else {
// have to build this on the fly because the collection has variable number of args
return MappedDeleteCollection.deleteObjects(databaseType, tableInfo, template, datas);
}
}
/**
* Delete a collection of objects from the database.
*/
public int deleteIds(JdbcTemplate template, Collection ids) throws SQLException {
if (idField == null) {
throw new SQLException("Cannot delete " + dataClass + " because it doesn't have an id field defined");
} else {
// have to build this on the fly because the collection has variable number of args
return MappedDeleteCollection.deleteIds(databaseType, tableInfo, template, ids);
}
}
/**
* Row mapper which handles our String[] raw results.
*/
private static class StringArrayRowMapper implements GenericRowMapper {
public String[] mapRow(ResultSet rs, int rowNum) throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
int colN = metaData.getColumnCount();
String[] result = new String[colN];
for (int colC = 0; colC < colN; colC++) {
result[colC] = rs.getString(colC + 1);
}
return result;
}
}
/**
* Base class for raw results objects;
*/
private abstract static class BaseRawResults implements RawResults {
protected final int columnN;
protected final String[] columnNames;
protected BaseRawResults(ResultSetMetaData metaData) throws SQLException {
this.columnN = metaData.getColumnCount();
this.columnNames = new String[this.columnN];
for (int colC = 0; colC < this.columnN; colC++) {
this.columnNames[colC] = metaData.getColumnName(colC + 1);
}
}
}
/**
* Raw results from a list of results.
*/
private static class RawResultsList extends BaseRawResults {
private final List results = new ArrayList();
public RawResultsList(ResultSetMetaData metaData) throws SQLException {
super(metaData);
}
public void add(String[] result) throws SQLException {
results.add(result);
}
public int size() {
return results.size();
}
public int getNumberColumns() {
return this.columnN;
}
public String[] getColumnNames() {
return columnNames;
}
public CloseableIterator iterator() {
return new RawResultsListIterator();
}
/**
* Internal iterator to work on our list.
*/
private class RawResultsListIterator implements CloseableIterator {
private int resultC = 0;
public boolean hasNext() {
return results.size() > resultC;
}
public String[] next() {
return results.get(resultC++);
}
public void remove() {
// noop
}
public void close() {
// noop
}
}
}
/**
* Raw results from an iterator.
*/
private static class RawResultsIterator extends BaseRawResults {
private final PreparedStatement statement;
private final String query;
public RawResultsIterator(String query, PreparedStatement statement) throws SQLException {
super(statement.getMetaData());
this.query = query;
this.statement = statement;
}
public int getNumberColumns() {
return this.columnN;
}
public String[] getColumnNames() {
return columnNames;
}
public CloseableIterator iterator() {
try {
// we do this so we can iterate through the results multiple times
return new SelectIterator(String[].class, null, StatementExecutor.stringArrayRowMapper,
statement, query);
} catch (SQLException e) {
// we have to do this because iterator can't throw Exceptions
throw new RuntimeException(e);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy