Steve
Steve

Reputation: 4681

Get Statement from JDBCTemplate

I have this code,

SimpleJdbcCall sql = new SimpleJdbcCall(dataSource).withProcedureName(procName);
sql.execute(parameters);

And I believe that under the hood this uses a JDBC Statement. How can I get to that object from here? (I need to call the .getWarnings() method on the statement).

In other words how can I get SQLWarnings AND named parameters?

Upvotes: 1

Views: 1735

Answers (2)

Steve
Steve

Reputation: 4681

It took a lot of digging, but here is how you can get SQLWarnings (or Print statements) AND named parameters. I extended JdbcTemplate and overrode the handleWarnings() method, and then passed that into my SimpleJdbcCall.

  public class JdbcTemplateLoggable extends JdbcTemplate{


    List<String> warnings;

    public JdbcTemplateLoggable(DataSource dataSource){
        super(dataSource);
        warnings = new ArrayList<String>();
    }

    protected void handleWarnings(Statement stmt){
        try {
            SQLWarning warning = stmt.getWarnings();
            while(warning != null){
                warnings.add(warning.getMessage());
                warning = warning.getNextWarning();
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public List<String> getWarnings(){
        return warnings;
    }
}

Then in my main program

JdbcTemplateLoggable template = new JdbcTemplateLoggable(dataSource);
        SimpleJdbcCall sql = new SimpleJdbcCall(template).withProcedureName(procName);
        sql.execute(parameters);
        for(String s : template.getWarnings()){
            log.info(s);
        }

Upvotes: 2

Florian Albrecht
Florian Albrecht

Reputation: 2326

You should perhaps use JdbcTemplate directly, or subclass it for usage with your SimpleJdbcCall (instead of a DataSource). JdbcTemplate has a method execute(CallableStatementCreator, CallableStatementCallback), where a callback can be passed which gets the used Statement object.

You could override that method and wrap the passed callback with an own which stores the statement for later use.

public class CustomJdbcTemplate extends JdbcTemplate {

    private CallableStatement lastStatement;

    public CustomJdbcTemplate(DataSource dataSource) {
        super(dataSource);
    }

    public CallableStatement getLastStatement() {
        return lastStatement;
    }

    @Override
    public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action) throws DataAccessException {
        StoringCallableStatementCallback<T> callback = new StoringCallableStatementCallback<T>(action); 
        try {
            return super.execute(csc, callback);
        }
        finally {
            this.lastStatement = callback.statement;
        }
    }

    private static class StoringCallableStatementCallback<T> implements CallableStatementCallback<T> {

        private CallableStatementCallback<T> delegate;

        private CallableStatement statement;

        private StoringCallableStatementCallback(CallableStatementCallback<T> delegate) {
            this.delegate = delegate;
        }

        @Override
        public T doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
            this.statement = cs;
            return delegate.doInCallableStatement(cs);
        }

    }

}

Note that the statement will most probably be closed when you retrieve it later, so getWarnings() may cause errors, depending on used JDBC driver. So maybe you should store the warnings instead of the statement itself.

Upvotes: 1

Related Questions