package ca.sqlpower.sql;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import org.apache.log4j.Logger;
/**
* The ResultSetClosingStatement class helps enforce the documented
* JDBC behaviour of "when a statement closes, so does its resultset."
*/
public class ResultSetClosingStatement implements Statement {
/**
* Just a log4j logger named after this class.
*/
static Logger logger = Logger.getLogger(ResultSetClosingStatement.class);
/**
* The actual statement that performs all the operations.
*/
protected Statement actualStatement;
/**
* The connection object that created this statement.
*/
protected Connection con;
/**
* The current result set (this implementation allows only one at a time).
*/
protected ResultSet results;
/**
* The last query that was attempted on this Statement. Useful if
* you get a SQLException and want to know what the query was.
*/
protected String lastQuery;
ResultSetClosingStatement(Connection con, Statement actualStmt) {
this.con=con;
this.actualStatement=actualStmt;
this.results=null;
}
public String getLastQuery() {
return lastQuery;
}
// ------------- java.sql.Statement interface -----------
/**
* Closes the current resultset (if there is one) then executes
* the given query. Also logs the given sql statement at DEBUG
* level before executing it.
*/
public ResultSet executeQuery(String sql) throws SQLException {
if (results != null) {
results.close();
}
long startTime = 0L;
long queryTime = 0L;
lastQuery = sql;
//
if (logger.isDebugEnabled()) {
logger.debug(sql.hashCode() + ", " + sql);
startTime = System.currentTimeMillis();
}
results = actualStatement.executeQuery(sql);
//
if (logger.isDebugEnabled()) {
queryTime = System.currentTimeMillis() - startTime;
logger.debug("low level query time for " + sql.hashCode() + " (ms): " + queryTime);
}
return results;
}
/**
* Executes the given statement without touching the existing
* resultset. Also logs the given sql statement at DEBUG level
* before executing it.
*/
public int executeUpdate(String sql) throws SQLException {
logger.debug(sql);
lastQuery = sql;
int rowCount = actualStatement.executeUpdate(sql);
logger.debug("Affected "+rowCount+" rows");
return rowCount;
}
public void close() throws SQLException {
if(results != null) {
results.close();
}
actualStatement.close();
}
public int getMaxFieldSize() throws SQLException {
return actualStatement.getMaxFieldSize();
}
public void setMaxFieldSize(int max) throws SQLException {
actualStatement.setMaxFieldSize(max);
}
public int getMaxRows() throws SQLException {
return actualStatement.getMaxRows();
}
public void setMaxRows(int max) throws SQLException {
actualStatement.setMaxRows(max);
}
public void setEscapeProcessing(boolean enable) throws SQLException {
actualStatement.setEscapeProcessing(enable);
}
public int getQueryTimeout() throws SQLException {
return actualStatement.getQueryTimeout();
}
public void setQueryTimeout(int seconds) throws SQLException {
actualStatement.setQueryTimeout(seconds);
}
public void cancel() throws SQLException {
actualStatement.cancel();
}
public SQLWarning getWarnings() throws SQLException {
return actualStatement.getWarnings();
}
public void clearWarnings() throws SQLException {
actualStatement.clearWarnings();
}
public void setCursorName(String name) throws SQLException {
actualStatement.setCursorName(name);
}
/**
* Not implemented because we allow only one result set per
* statement (at a time).
*/
public boolean execute(String sql) throws SQLException {
throw new UnsupportedOperationException("Not allowed by ResultSetClosingStatement");
}
public ResultSet getResultSet() throws SQLException {
return results;
}
public int getUpdateCount() throws SQLException {
return actualStatement.getUpdateCount();
}
/**
* Not implemented because we allow only one result set per
* statement (at a time).
*/
public boolean getMoreResults() throws SQLException {
throw new UnsupportedOperationException("Not allowed by ResultSetClosingStatement");
}
public void setFetchDirection(int direction) throws SQLException {
actualStatement.setFetchDirection(direction);
}
public int getFetchDirection() throws SQLException {
return actualStatement.getFetchDirection();
}
public void setFetchSize(int rows) throws SQLException {
actualStatement.setFetchSize(rows);
}
public int getFetchSize() throws SQLException {
return actualStatement.getFetchSize();
}
public int getResultSetConcurrency() throws SQLException {
return actualStatement.getResultSetConcurrency();
}
public int getResultSetType() throws SQLException {
return actualStatement.getResultSetType();
}
public void addBatch( String sql ) throws SQLException {
actualStatement.addBatch(sql);
}
public void clearBatch() throws SQLException {
actualStatement.clearBatch();
}
public int[] executeBatch() throws SQLException {
return actualStatement.executeBatch();
}
public Connection getConnection() throws SQLException {
return con;
}
/**
* Closes the result set. If a SQLException results, it is logged
* at WARN level.
*/
public void finalize() {
try {
if(results != null) {
results.close();
}
} catch (SQLException e) {
logger.warn("Couldn't close result set in finalizer: "+e);
}
}
/**
* @see java.sql.Statement#execute(String, int)
*/
public boolean execute(String sql, int autoGeneratedKeys)
throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#execute(String, int[])
*/
public boolean execute(String sql, int[] columnIndexes)
throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#execute(String, String[])
*/
public boolean execute(String sql, String[] columnNames)
throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#executeUpdate(String, int)
*/
public int executeUpdate(String sql, int autoGeneratedKeys)
throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#executeUpdate(String, int[])
*/
public int executeUpdate(String sql, int[] columnIndexes)
throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#executeUpdate(String, String[])
*/
public int executeUpdate(String sql, String[] columnNames)
throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#getGeneratedKeys()
*/
public ResultSet getGeneratedKeys() throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#getMoreResults(int)
*/
public boolean getMoreResults(int current) throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
/**
* @see java.sql.Statement#getResultSetHoldability()
*/
public int getResultSetHoldability() throws SQLException {
throw new UnsupportedOperationException("Not implemented yet...");
}
public boolean isClosed() throws SQLException {
throw new UnsupportedOperationException("Currently it is only possible to wrap JDBC 3.");
}
public boolean isPoolable() throws SQLException {
throw new UnsupportedOperationException("Currently it is only possible to wrap JDBC 3.");
}
public void setPoolable(boolean arg0) throws SQLException {
throw new UnsupportedOperationException("Currently it is only possible to wrap JDBC 3.");
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
throw new UnsupportedOperationException("Currently it is only possible to wrap JDBC 3.");
}
public <T> T unwrap(Class<T> iface) throws SQLException {
throw new UnsupportedOperationException("Currently it is only possible to wrap JDBC 3.");
}
@Override
public void closeOnCompletion() throws SQLException {
actualStatement.closeOnCompletion();
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
return actualStatement.isCloseOnCompletion();
}
}