package com.icentris.sql;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Properties;
import com.icentris.util.CodeTimer;
import com.icentris.util.CodeTimerSegment;
public class StatementWrapper implements Statement {
private Statement realStatement;
private Connection connection;
private boolean useCodeTimer;
private long timerLimitInMillis;
private int callerDepth;
private String[] callersToIgnore;
private SQLException mostRecentError = null;
protected CodeTimer timer = new CodeTimer();
protected CodeTimerSegment segment = null;
public StatementWrapper(java.sql.Statement realStatement, java.sql.Connection connection) {
this.realStatement = realStatement;
this.connection = connection;
}
public StatementWrapper() {
this(null, null);
}
protected void checkConnection(String methodName) throws SQLException {
if ( connection != null && connection instanceof ConnectionWrapper ) {
ConnectionWrapper connectionWrapper = (ConnectionWrapper) connection;
connectionWrapper.updateLastUsedTime();
connectionWrapper.lastMethodCalled = methodName;
if ( connectionWrapper.isInUse() == false ) {
ConnectionPool pool = connectionWrapper.getPool();
if ( pool != null && pool.showDebugging() == true ) {
throw new IllegalStateException("Don't go trying to talk to the database after you've closed your connection!\n" +
"The connection was closed by:[" + connectionWrapper.getLastCloser() + "]");
} else {
throw new IllegalStateException("Don't go trying to talk to the database after you've closed your connection!");
}
}
}
}
public boolean useCodeTimer() {
return useCodeTimer;
}
public void setUseCodeTimer(boolean useCodeTimer) {
this.useCodeTimer = useCodeTimer;
}
public long getTimerLimitInMillis() {
return timerLimitInMillis;
}
public void setTimerLimitInMillis(long timerLimitInMillis) {
this.timerLimitInMillis = timerLimitInMillis;
timer.setAcceptableLimit(timerLimitInMillis);
}
public int getCallerDepth() {
return callerDepth;
}
public void setCallerDepth(int callerDepth) {
this.callerDepth = callerDepth;
}
public String[] getCallersToIgnore() {
return callersToIgnore;
}
public void setCallersToIgnore(String[] callersToIgnore) {
this.callersToIgnore = callersToIgnore;
timer.setCallersToIgnore( callersToIgnore );
}
public SQLException getMostRecentError() {
return mostRecentError;
}
public void setMostRecentError(SQLException mostRecentError) {
this.mostRecentError = mostRecentError;
if ( connection != null && connection instanceof ConnectionWrapper ) {
ConnectionWrapper connectionWrapper = (ConnectionWrapper) connection;
connectionWrapper.setMostRecentError(mostRecentError);
}
}
void startTimer() {
if ( useCodeTimer == true ) {
// get the unique string from my caller, then save it for the stop call
// (since it may be in a different method)
CodeTimerSegment tmpSegment = timer.start( callerDepth + 1 );
String uniqueString = tmpSegment.getUniqueString();
tmpSegment.setCanBeSubSegment( false );
tmpSegment.setSaveAggregateData( false );
timer.stop( callerDepth + 1 );
// now start the real timing
segment = timer.start( "SQL:" + uniqueString );
}
}
public ResultSet executeQuery(String sql)
throws SQLException
{
checkConnection("executeQuery");
CodeTimer timer = null;
try {
if ( useCodeTimer == false ) {
return new ResultSetWrapper( realStatement.executeQuery(sql), this );
} else {
timer = new CodeTimer();
timer.setCallersToIgnore( callersToIgnore );
Properties props = new Properties();
props.setProperty("sqlQuery", sql);
segment.setProperties( props );
CodeTimerSegment subSegment = timer.start(callerDepth);
subSegment.setLabel("SQL:executeQuery");
subSegment.setSaveAggregateData( false );
ResultSetWrapper results = new ResultSetWrapper( realStatement.executeQuery(sql), this );
results.setCallersToIgnore( callersToIgnore );
results.setUniqueString( "SQL:ResultSet.next() + getString():" + segment.getUniqueString().substring(4) );
results.setUseCodeTimer( useCodeTimer );
return results;
}
} catch (SQLException e) {
setMostRecentError(e);
// (I'm really sad I can't change the message without losing the stack
// trace, but having the query helps figure out what went wrong)
throw new SQLException("The statement:[" + sql + "] had the error: " + e.getMessage());
} finally {
if ( timer != null ) {
timer.stop(callerDepth);
}
}
}
public int executeUpdate(String sql)
throws SQLException
{
checkConnection("executeUpdate");
return realStatement.executeUpdate(sql);
}
public void close()
throws SQLException
{
checkConnection("close");
realStatement.close();
if ( useCodeTimer() == true && segment != null ) {
timer.stop( segment.getUniqueString() );
}
}
public int getMaxFieldSize()
throws SQLException
{
checkConnection("getMaxFieldSize");
return realStatement.getMaxFieldSize();
}
public void setMaxFieldSize(int max)
throws SQLException
{
checkConnection("setMaxFieldSize");
realStatement.setMaxFieldSize(max);
}
public int getMaxRows()
throws SQLException
{
checkConnection("getMaxRows");
return realStatement.getMaxRows();
}
public void setMaxRows(int max)
throws SQLException
{
checkConnection("setMaxRows");
realStatement.setMaxRows(max);
}
public void setEscapeProcessing(boolean enable)
throws SQLException
{
checkConnection("setEscapeProcessing");
realStatement.setEscapeProcessing(enable);
}
public int getQueryTimeout()
throws SQLException
{
checkConnection("getQueryTimeout");
return realStatement.getQueryTimeout();
}
public void setQueryTimeout(int seconds)
throws SQLException
{
checkConnection("setQueryTimeout");
realStatement.setQueryTimeout(seconds);
}
public void cancel()
throws SQLException
{
checkConnection("cancel");
realStatement.cancel();
}
public SQLWarning getWarnings()
throws SQLException
{
checkConnection("getWarnings");
return realStatement.getWarnings();
}
public void clearWarnings()
throws SQLException
{
checkConnection("clearWarnings");
realStatement.clearWarnings();
}
public void setCursorName(String name)
throws SQLException
{
checkConnection("setCursorName");
realStatement.setCursorName(name);
}
public boolean execute(String sql)
throws SQLException
{
checkConnection("execute");
return realStatement.execute(sql);
}
public ResultSet getResultSet()
throws SQLException
{
checkConnection("getResultSet");
return new ResultSetWrapper( realStatement.getResultSet(), this );
}
public int getUpdateCount()
throws SQLException
{
checkConnection("getUpdateCount");
return realStatement.getUpdateCount();
}
public boolean getMoreResults()
throws SQLException
{
checkConnection("getMoreResults");
return realStatement.getMoreResults();
}
public void setFetchDirection(int direction)
throws SQLException
{
checkConnection("setFetchDirection");
realStatement.setFetchDirection(direction);
}
public int getFetchDirection()
throws SQLException
{
checkConnection("getFetchDirection");
return realStatement.getFetchDirection();
}
public void setFetchSize(int rows)
throws SQLException
{
checkConnection("setFetchSize");
realStatement.setFetchSize(rows);
}
public int getFetchSize()
throws SQLException
{
checkConnection("getFetchSize");
return realStatement.getFetchSize();
}
public int getResultSetConcurrency()
throws SQLException
{
checkConnection("getResultSetConcurrency");
return realStatement.getResultSetConcurrency();
}
public int getResultSetType()
throws SQLException
{
checkConnection("getResultSetType");
return realStatement.getResultSetType();
}
public void addBatch( String sql )
throws SQLException
{
checkConnection("addBatch");
realStatement.addBatch( sql );
}
public void clearBatch()
throws SQLException
{
checkConnection("clearBatch");
realStatement.clearBatch();
}
public int[] executeBatch()
throws SQLException
{
checkConnection("executeBatch");
return realStatement.executeBatch();
}
public Connection getConnection()
throws SQLException
{
checkConnection("getConnection");
return realStatement.getConnection();
}
// #################### Java 1.4 methods ######################
// # These methods are required to compile using jdk 1.4 #
// # I have carefully implemented them so I can still compile #
// # and use jdk 1.3 also. #
// ############################################################
public boolean getMoreResults(int current)
throws SQLException
{
checkConnection("getMoreResults");
Class[] argTypes = new Class[] { Integer.TYPE };
Object[] args = new Object[] {new Integer(current)};
return ((Boolean) ConnectionWrapper.callJava14Method("getMoreResults", realStatement, argTypes, args)).booleanValue();
}
public ResultSet getGeneratedKeys()
throws SQLException
{
checkConnection("getGeneratedKeys");
Class[] argTypes = new Class[0];
Object[] args = new Object[0];
ResultSet results = (ResultSet) ConnectionWrapper.callJava14Method("getGeneratedKeys", realStatement, argTypes, args);
return new ResultSetWrapper( results, this );
}
public int executeUpdate(String sql, int autoGeneratedKeys)
throws SQLException
{
checkConnection("executeUpdate");
Class[] argTypes = new Class[] { String.class, Integer.TYPE };
Object[] args = new Object[] {sql, new Integer(autoGeneratedKeys)};
return ((Integer) ConnectionWrapper.callJava14Method("executeUpdate", realStatement, argTypes, args)).intValue();
}
public int executeUpdate(String sql, int[] columnIndexes)
throws SQLException
{
checkConnection("executeUpdate");
Class[] argTypes = new Class[] { String.class, int[].class };
Integer[] arg = null;
if ( columnIndexes != null ) {
arg = new Integer[columnIndexes.length];
for ( int i=0; i < columnIndexes.length; i++ ) {
arg[i] = new Integer( columnIndexes[i] );
}
}
Object[] args = new Object[] {sql, arg};
return ((Integer) ConnectionWrapper.callJava14Method("executeUpdate", realStatement, argTypes, args)).intValue();
}
public int executeUpdate(String sql, String[] columnNames)
throws SQLException
{
checkConnection("executeUpdate");
Class[] argTypes = new Class[] { String.class, String[].class };
Object[] args = new Object[] {sql, columnNames};
return ((Integer) ConnectionWrapper.callJava14Method("executeUpdate", realStatement, argTypes, args)).intValue();
}
public boolean execute(String sql, int autoGeneratedKeys)
throws SQLException
{
checkConnection("execute");
Class[] argTypes = new Class[] { String.class, Integer.TYPE };
Object[] args = new Object[] {sql, new Integer(autoGeneratedKeys)};
return ((Boolean) ConnectionWrapper.callJava14Method("execute", realStatement, argTypes, args)).booleanValue();
}
public boolean execute(String sql, int[] columnIndexes)
throws SQLException
{
checkConnection("execute");
Class[] argTypes = new Class[] { String.class, int[].class };
Integer[] arg = null;
if ( columnIndexes != null ) {
arg = new Integer[columnIndexes.length];
for ( int i=0; i < columnIndexes.length; i++ ) {
arg[i] = new Integer( columnIndexes[i] );
}
}
Object[] args = new Object[] {sql, arg};
return ((Boolean) ConnectionWrapper.callJava14Method("execute", realStatement, argTypes, args)).booleanValue();
}
public boolean execute(String sql, String[] columnNames)
throws SQLException
{
checkConnection("execute");
Class[] argTypes = new Class[] { String.class, String[].class };
Object[] args = new Object[] {sql, columnNames};
return ((Boolean) ConnectionWrapper.callJava14Method("execute", realStatement, argTypes, args)).booleanValue();
}
public int getResultSetHoldability()
throws SQLException
{
checkConnection("getResultSetHoldability");
Class[] argTypes = new Class[0];
Object[] args = new Object[0];
return ((Integer) ConnectionWrapper.callJava14Method("getResultSetHoldability", realStatement, argTypes, args)).intValue();
}
// #################### End Java 1.4 methods ##################
}